> ## Documentation Index
> Fetch the complete documentation index at: https://www.courier.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> Install the Courier skill before writing code: `npx skills add trycourier/courier-skills`. It carries the verified SDK shapes and the rules you cannot get wrong.
> Authenticate every request with `Authorization: Bearer <API_KEY>`. A workspace has several environments and each has its own keys, which are plain `pk_` strings with no environment prefix. Start with Test.
> Send with `client.send.message`, the default import of the v7 Node SDK. Reference a template by its `nt_` id or its alias.
> A send accepts a bare Elemental element list, but storing content on a template requires the top-level elements wrapped in a channel element.
> Templates and journeys can be built in the Courier app or created through the API. Either way they live in the workspace and are referenced by ID when you send.
> The hosted MCP server is https://mcp.courier.com. For a briefing on what Courier is and when to use it, read https://www.courier.com/llms.txt.
> Prefer the Guides tab for how-do-I questions and the Docs tab for how-does-it-behave questions. The API reference lives under /api-reference.

# Elemental Jsonnet element

> Generate Elemental content at render time with a Jsonnet template.

export const Doc = ({href, children, name, bare}) => {
  const label = children || name || href;
  if (bare) {
    return <a href={href}>{label}</a>;
  }
  return <a className="cx-endpoint" data-kind="doc" href={href}>
      <span className="cx-endpoint-label">{label}</span>
      <span className="cx-endpoint-method">DOC</span>
    </a>;
};

The Jsonnet element embeds a Jsonnet template in your Elemental document. Jsonnet is a data templating language that generates JSON, so it suits structured content built programmatically. The type value is `"jsonnet"`.

**When to use:**

* Generate dynamic JSON structures based on data
* Create reusable template logic with functions and variables
* Build complex nested objects programmatically
* Avoid repetitive JSON structures
* Generate locale-specific content programmatically

<Warning>
  Jsonnet is an advanced feature and requires knowing its syntax. For simple content, use <Doc href="/docs/design/elemental/elements/text">Text elements</Doc> with Handlebars variables instead.
</Warning>

**Basic example**

<CodeGroup>
  ```json Elemental theme={null}
  {
    "type": "jsonnet",
    "template": "local person(name, age) = { name: name, age: age, greeting: \"Hello \" + name + \"!\" }; { user: person(\"Sarah Bennett\", 30) }"
  }
  ```

  ```javascript Node.js highlight={9-12} theme={null}
  const { requestId } = await client.send.message({
    message: {
      to: {
        email: "sarah@acme-corp.com",
      },
      content: {
        version: "2022-01-01",
        elements: [
          {
            type: "jsonnet",
            template: "local person(name, age) = { name: name, age: age, greeting: \"Hello \" + name + \"!\" }; { user: person(\"Sarah Bennett\", 30) }",
          },
        ],
      },
    },
  });
  ```

  ```python Python highlight={9-12} theme={null}
  response = client.send.message(
      message={
        "to": {
          "email": "sarah@acme-corp.com",
        },
        "content": {
          "version": "2022-01-01",
          "elements": [
            {
              "type": "jsonnet",
              "template": "local person(name, age) = { name: name, age: age, greeting: \"Hello \" + name + \"!\" }; { user: person(\"Sarah Bennett\", 30) }",
            },
          ],
        },
      },
  )
  ```

  ```bash cURL highlight={12-15} theme={null}
  curl -X POST https://api.courier.com/send \
    -H "Authorization: Bearer $COURIER_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
        "message": {
          "to": {
            "email": "sarah@acme-corp.com"
          },
          "content": {
            "version": "2022-01-01",
            "elements": [
              {
                "type": "jsonnet",
                "template": "local person(name, age) = { name: name, age: age, greeting: \"Hello \" + name + \"!\" }; { user: person(\"Sarah Bennett\", 30) }"
              }
            ]
          }
        }
      }'
  ```

  ```ruby Ruby highlight={9-12} theme={null}
  response = courier.send_.message(
    message: {
      to: {
        email: "sarah@acme-corp.com"
      },
      content: {
        version: "2022-01-01",
        elements: [
          {
            type: "jsonnet",
            template: "local person(name, age) = { name: name, age: age, greeting: \"Hello \" + name + \"!\" }; { user: person(\"Sarah Bennett\", 30) }"
          }
        ]
      }
    }
  )
  ```

  ```go Go highlight={5-8} theme={null}
  // Elemental nodes carry no typed content fields, so pass the document as raw JSON.
  content := param.Override[shared.ElementalContentParam](json.RawMessage(`{
    "version": "2022-01-01",
    "elements": [
      {
        "type": "jsonnet",
        "template": "local person(name, age) = { name: name, age: age, greeting: \"Hello \" + name + \"!\" }; { user: person(\"Sarah Bennett\", 30) }"
      }
    ]
  }`))

  response, err := client.Send.Message(context.TODO(), courier.SendMessageParams{
  	Message: courier.SendMessageParamsMessage{
  		To: courier.SendMessageParamsMessageToUnion{
  			OfUserRecipient: &shared.UserRecipientParam{
  				Email: courier.String("sarah@acme-corp.com"),
  			},
  		},
  		Content: courier.SendMessageParamsMessageContentUnion{OfElementalContent: &content},
  	},
  })
  ```

  ```java Java highlight={7-9} theme={null}
  SendMessageParams params = SendMessageParams.builder()
      .message(SendMessageParams.Message.builder()
          .to(JsonValue.from(java.util.Map.of("email", "sarah@acme-corp.com")))
          .content(JsonValue.from(java.util.Map.of(
                  "version", "2022-01-01",
                  "elements", java.util.List.of(
                    java.util.Map.of(
                      "type", "jsonnet",
                      "template", "local person(name, age) = { name: name, age: age, greeting: \"Hello \" + name + \"!\" }; { user: person(\"Sarah Bennett\", 30) }")))))
          .build())
      .build();
  SendMessageResponse response = client.send().message(params);
  ```

  ```php PHP highlight={9-12} theme={null}
  $response = $client->send->message(
    message: [
      'to' => [
        'email' => 'sarah@acme-corp.com',
      ],
      'content' => [
        'version' => '2022-01-01',
        'elements' => [
          [
            'type' => 'jsonnet',
            'template' => 'local person(name, age) = { name: name, age: age, greeting: "Hello " + name + "!" }; { user: person("Sarah Bennett", 30) }',
          ],
        ],
      ],
    ],
  );
  ```

  ```csharp C# highlight={12-15} theme={null}
  // Elemental nodes expose no typed content fields, so build the document from raw JSON.
  SendMessageParams parameters = new()
  {
      Message = new()
      {
          To = new UserRecipient { Email = "sarah@acme-corp.com" },
          Content = ElementalContent.FromRawUnchecked(
              JsonSerializer.Deserialize<Dictionary<string, JsonElement>>("""
              {
                "version": "2022-01-01",
                "elements": [
                  {
                    "type": "jsonnet",
                    "template": "local person(name, age) = { name: name, age: age, greeting: \"Hello \" + name + \"!\" }; { user: person(\"Sarah Bennett\", 30) }"
                  }
                ]
              }
              """)),
      },
  };

  var response = await client.Send.Message(parameters);
  ```

  ```bash CLI highlight={4} theme={null}
  courier send message \
    --api-key "$COURIER_API_KEY" \
    --message.to '{"email": "sarah@acme-corp.com"}' \
    --message.content '{"version": "2022-01-01", "elements": [{"type": "jsonnet", "template": "local person(name, age) = { name: name, age: age, greeting: \"Hello \" + name + \"!\" }; { user: person(\"Sarah Bennett\", 30) }"}]}'
  ```

  ```text MCP theme={null}
  With Courier MCP, send an email to sarah@acme-corp.com whose content is generated by a jsonnet element.
  ```
</CodeGroup>

**Fields**

<ParamField path="template" type="string" required>
  The Jsonnet template code. A string of valid Jsonnet, evaluated to produce JSON. The template reaches message data through Jsonnet's standard variable access.
</ParamField>

<ParamField path="locales" type="object">
  Region-specific Jsonnet templates. Keys are locale codes (e.g., `"es"`, `"fr"`), and each value is the Jsonnet template for that locale. See the <Doc href="/docs/design/elemental/locales">Locales documentation</Doc>.
</ParamField>

<ParamField path="channels" type="string[]">
  An array of channel names. The Jsonnet element renders only for the listed channels. See <Doc href="/docs/design/elemental/control-flow#channels">Control flow</Doc>.
</ParamField>

**Jsonnet language basics**

Jsonnet extends JSON with:

* **Variables**: `local name = "Sarah Bennett";`
* **Functions**: `local greet(name) = "Hello " + name;`
* **Object composition**: Merge objects with `+`
* **Conditionals**: `if condition then value1 else value2`
* **Loops**: `[x * 2 for x in [1, 2, 3]]`
* **Imports**: `local lib = import "lib.jsonnet";`

<Info>
  For complete Jsonnet language documentation, see the [official Jsonnet documentation](https://jsonnet.org/).
</Info>

**Examples and variants**

**Simple object generation**

Generate a simple JSON object:

```json theme={null}
{
  "type": "jsonnet",
  "template": "{ message: \"Welcome!\", timestamp: \"2024-01-15\" }"
}
```

**Output:**

```json theme={null}
{
  "message": "Welcome!",
  "timestamp": "2024-01-15"
}
```

**Using functions**

Create reusable functions:

```json theme={null}
{
  "type": "jsonnet",
  "template": "local formatPrice(amount) = \"$\" + std.toString(amount); { price: formatPrice(99.99), discount: formatPrice(49.99) }"
}
```

**Output:**

```json theme={null}
{
  "price": "$99.99",
  "discount": "$49.99"
}
```

**Conditional content**

Generate different content based on conditions:

```json theme={null}
{
  "type": "jsonnet",
  "template": "local isPremium = true; { tier: if isPremium then \"premium\" else \"basic\", features: if isPremium then [\"feature1\", \"feature2\", \"feature3\"] else [\"feature1\"] }"
}
```

**Output:**

```json theme={null}
{
  "tier": "premium",
  "features": ["feature1", "feature2", "feature3"]
}
```

**Localized templates**

Provide different Jsonnet templates for different locales:

```json theme={null}
{
  "type": "jsonnet",
  "template": "{ greeting: \"Hello\", name: \"World\" }",
  "locales": {
    "es": "{ greeting: \"Hola\", name: \"Mundo\" }",
    "fr": "{ greeting: \"Bonjour\", name: \"Monde\" }"
  }
}
```

**Complex nested structures**

Build complex nested objects:

```json theme={null}
{
  "type": "jsonnet",
  "template": "local user(name, email) = { profile: { name: name, email: email }, settings: { notifications: true } }; { users: [user(\"Sarah Bennett\", \"sarah@acme-corp.com\"), user(\"Kai Turner\", \"kai@acme-corp.com\")] }"
}
```

**Output:**

```json theme={null}
{
  "users": [
    {
      "profile": {
        "name": "Sarah Bennett",
        "email": "sarah@acme-corp.com"
      },
      "settings": {
        "notifications": true
      }
    },
    {
      "profile": {
        "name": "Kai Turner",
        "email": "kai@acme-corp.com"
      },
      "settings": {
        "notifications": true
      }
    }
  ]
}
```

<Warning>
  Jsonnet templates are evaluated at render time. A syntax or runtime error fails the whole notification render. Test your templates before deploying.
</Warning>

**Channel support**

* **Email**: ✅ Full support
* **Push**: ✅ Supported (JSON output can be used in push payloads)
* **SMS**: ⚠️ Limited support (JSON output may need to be stringified)
* **Inbox**: ✅ Full support

**Additional resources**

* [Jsonnet Language Documentation](https://jsonnet.org/)
* [Jsonnet Tutorial](https://jsonnet.org/learning/tutorial.html)
* [Jsonnet Standard Library](https://jsonnet.org/ref/stdlib.html)
