Template substitution error while using secure iparam (API Key) in request template in freshservice

Hi Team,

I’m encountering an “error while substituting templates” while invoking a request template in my Freshservice app.

The API key is stored as a secure iparam, and I’m using that secure iparam in the request template’s Authorization header. However, the request fails before it reaches the API.

Error:

Status: 400
Response: error while substituting templates.

The API key is configured correctly as a secure iparam, but template substitution fails when the request is invoked.

request.json
{ “schema”: { “method”: “GET”, “host”: “https://.freshservice.com”, “path”: “/api/v2/workspaces”, “headers”: { “Authorization”: “Basic <%= encode(iparam.api_key) %>”, “Content-Type”: “application/json” } } }

Hi @TAMIL, “error while substituting templates” means FDK couldn’t resolve a template variable before the HTTP call goes out. It’s usually a host format or iparam name/config issue, not the API key value itself.

Issues in your template

1. Invalid host (most likely)
Your host is "https://.freshservice.com"- two problems:

  • https:// must not be in host: use "protocol": "https" separately
  • Subdomain is missing: host must be a full FQDN
"protocol": "https",
"host": "<%= iparam.domain %>.freshservice.com",
"path": "/api/v2/workspaces"

2. Secure iparam placement
Secure iparams work only in headers - not in host, path, or query. Put the subdomain in a non-secure iparam (domain).

3. Iparam name must match exactly
If iparams.json defines apiKey but the template uses iparam.api_key, substitution fails. Names are case-sensitive.


Correct pattern for Freshservice

config/requests.json:

{
  "getWorkspaces": {
    "schema": {
      "protocol": "https",
      "method": "GET",
      "host": "<%= iparam.domain %>.freshservice.com",
      "path": "/api/v2/workspaces",
      "headers": {
        "Authorization": "Basic <%= encode(iparam.api_key) %>",
        "Content-Type": "application/json"
      }
    }
  }
}

config/iparams.json:

{
  "domain": {
    "display_name": "Freshservice subdomain",
    "type": "text",
    "required": true
  },
  "api_key": {
    "display_name": "API Key",
    "type": "text",
    "required": true,
    "secure": true
  }
}

manifest.json: declare the template under modules.common.requests.


Local testing checklist

  1. Set iparam values at http://localhost:10001/custom_configs
  2. fdk validate: fix any template errors first
  3. Template name must match in requests.json, manifest.json, and invokeTemplate('getWorkspaces', …)
  4. Hardcode host temporarily to isolate: if static host works but <%= iparam.domain %> fails → iparam name/config issue

Rule of thumb

Field Secure iparam? Format
host No subdomain.freshservice.com (no protocol)
headers.Authorization Yes Basic <%= encode(iparam.api_key) %>

Docs: Request method - template substitutions

Thanks for the suggestions.

I’m already using the correct URL format. The domain iparam contains only the hostname (e.g. organization.freshservice.com) and does not include https://.

The same API works successfully:

  • From the backend using context.

  • From the config page.

The issue occurs only in the frontend when using client.request.invokeTemplate().

This is the request template I’m using:

"getRoles": {
  "schema": {
    "protocol": "https",
    "method": "GET",
    "host": "<%= iparam.domain %>",
    "path": "/api/v2/roles",
    "headers": {
      "Authorization": "Basic <%= encode(iparam.api_key) %>",
      "Content-Type": "application/json"
    }
  }
}

This is how I’m save this in postconfig.

let params = {
  __meta: {
    secure: ["api_key", "domain", "azure_token"]
  }
};

const response = await client.request.invokeTemplate("getRoles", {});

Since the exact same API works in the backend and config page, I don’t think it’s a host format or API key issue.

Could you please let me know if there’s anything specific I’m missing for frontend client.request.invokeTemplate() with iparam substitution?

Hi Team,

I identified the reason for the “error while substituting templates” issue.

The values required by the request template are already stored as iparams. This includes both secure and normal iparams. The issue occurs when we retrieve an already configured iparam value through context and pass it to the request template.

The main issue is that, if a key name is already present as an iparam, passing the same key name through context causes a template substitution error.

For example, if domain is already configured as an iparam, and we pass domain again through context:

context: {
    domain: value
}

and use:

<%= context.domain %>

it results in a template substitution error.

Similarly, if project_id is already configured as an iparam, but we need to pass a different/dynamic project ID through context using the same key:

context: {
    project_id: value
}

this also results in a template substitution error.

However, if the context key is different from the existing iparam key, there is no issue and the request works successfully.

For example:

context: {
    dynamic_project_id: value
}

works because dynamic_project_id is not an existing iparam key.

However, when the same value is directly referenced from the iparam:

<%= iparam.domain %>

the template works correctly.

The same approach is used for the secure api_key:

<%= encode(iparam.api_key) %>

So the working approach is to directly reference values that are already configured as iparams using iparam.<parameter_name>, instead of passing those same iparam values again through context.

This works for both:

  • Secure iparams such as api_key

  • Normal iparams such as domain

Therefore, the template substitution issue has been resolved by directly using the configured iparam values in the request template and avoiding the use of the same key name in both iparam and context.

Thanks.