back to tutorials

How to Use the Structured Fetch Ability Action

Learn how to use ChatBotKit's structured fetch ability action to make HTTP requests from your bot. Compare the simple placeholder format, the structured YAML format, and the YAML tags format with typed field tags like !fetch, !string, and !reference.

In this tutorial, you will learn how to use ChatBotKit's structured fetch ability action to make HTTP requests from your bot. You will see three ways to define a fetch action - the simple placeholder format, the structured YAML format, and the YAML tags format - and how to connect secrets for API authentication, both for administrator-managed and end-user-authenticated scenarios.

What You Will Learn

  • How to write a fetch ability using the simple format with placeholders
  • How to write the same ability using the structured YAML format with typed field tags
  • How to write the same ability using YAML tags (!fetch, !string, etc.) for fully typed, machine-parseable definitions
  • When to choose one format over the other
  • How to authenticate API calls using secrets
  • The difference between admin-managed secrets and user-authenticated secrets

Prerequisites

The Simple Format

The simple format uses backtick-delimited fetch code blocks inside the ability instruction. The AI model reads the instruction text and fills in any placeholders before executing the request.

Example: Fetching Weather Data

In this format:

  • The instruction is free-form text mixed with one or more fetch code blocks.
  • Placeholders like {location} are filled in by the AI model based on context from the conversation.
  • You can include natural-language descriptions around the code block to guide the model's behavior.
  • The HTTP request inside the code block follows a raw HTTP-like syntax with the method, URL, and headers.

This format works well for simple, public APIs that do not require authentication. The AI model has full flexibility to decide how to construct the request.

The Structured Format

The structured format uses YAML with special field tags to define the request in a more precise, machine-readable way. Instead of the AI model interpreting free-form text, it fills in explicitly declared fields with specific types and descriptions.

Example: Fetching Weather Data (Structured)

In this format:

  • The entire instruction is a single fetch code block containing YAML.
  • Field placeholders use a typed bracket syntax instead of plain {location}.
  • Static values like units: metric are passed through as-is.
  • Secrets are referenced with ${SECRET_DEFAULT} or ${SECRET_NAME} and are resolved at execution time.

Field Placeholder Syntax

The structured format supports three types of field placeholders:

SyntaxNamePurpose
$[name! ys|description]AI-extracted fieldThe AI fills in this value based on the conversation
((name! ys|description))Template placeholderA value provided by the user or preset in the template
${SECRET_DEFAULT}Secret referenceReplaced with the resolved secret value at runtime

Each placeholder has the following parts:

  • name - the field identifier (e.g., location, query, apiKey)
  • ! - marks the field as required (omit for optional fields)
  • ys - an operand that controls value formatting (ys = YAML string escaping)
  • description - a human-readable hint that guides the AI or the user

Other common operands include:

OperandDescription
ysYAML string - handles string escaping for YAML values
eucURL-encode the value
jsJSON stringify the value
trimTrim whitespace from the value

Structured YAML Properties

The structured fetch action supports the following top-level YAML properties:

PropertyDescription
methodHTTP method: GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS
urlThe base URL of the API endpoint
pathURL path segments (can include dynamic fields)
queryQuery string parameters as key-value pairs
headersHTTP headers as key-value pairs
bodyRequest body - a string or object for POST/PUT requests
options.formatResponse format: text, markdown, json, or toon

The YAML Tags Format

The YAML tags format uses custom YAML tags like !fetch, !string, !number, !boolean, !reference, and !concat to define every part of the request in a fully typed, machine-parseable way. Instead of placeholder syntax like ((name! ys|description)), each dynamic field is an explicit YAML node with its own properties.

This format is defined in the platform's action tags system and is the most precise way to describe a fetch action.

Example: Fetching Weather Data (YAML Tags)

In this format:

  • The !fetch tag at the top declares this as a fetch action.
  • !string declares a typed input field with a name and description. The AI fills in the value based on the conversation.
  • !reference SECRET_DEFAULT resolves to the secret linked to the ability, identical to ${SECRET_DEFAULT} in other formats.
  • Static values like units: metric are passed through unchanged.
  • You can add an options block (e.g., format) exactly like in the structured format.

Available Field Tags

TagPurposeKey properties
!stringA text input fieldname, description, default, enum, min, max, transform
!numberA numeric input fieldname, description, default, enum, min, max
!booleanA true/false input fieldname, description, default
!arrayAn array input fieldname, description, items (nested field schema)
!objectAn object input fieldname, description, properties (named nested fields)

Each tag also supports optional (defaults to false) and placeholder.

Appending ? to any field tag (e.g., !string?, !number?) is a shorthand for marking the field as optional.

Optional Fields

You can mark a field as optional either by setting the optional property or by using the shorthand ? tag variant:

Here, query is required and limit is optional with a default value of 10. If the user does not provide a limit, the default is used automatically.

Building Dynamic Strings with !concat

Use !concat to assemble a string from multiple parts, combining static text with dynamic field values:

!concat takes a sequence of values (strings, numbers, booleans, or field tags) and joins them into a single string.

Referencing Secrets with !reference

The !reference tag is a scalar tag that resolves named values at execution time. It is commonly used for secrets:

This is equivalent to ${SECRET_DEFAULT} in the other formats, but as a proper YAML node it integrates cleanly with the rest of the tag system.

Dynamic Query and Body Fields

You can mix static and dynamic values freely in query parameters and request bodies:

Field Transforms

String fields support transforms that modify the value before it is used:

Available transforms: lower, upper, trim, urlencode. Transforms are applied in order.

Field Enums

String and number fields can restrict their values to a predefined set using enum:

Simple vs Structured vs YAML Tags: Side-by-Side Comparison

Here is the same ability written in all three formats to highlight the differences.

Goal: Create an ability that searches for GitHub repositories by keyword.

Simple Format

Structured Format

YAML Tags Format

When to Use Each Format

ConsiderationSimple FormatStructured FormatYAML Tags Format
Ease of writingEasiest - looks like a raw HTTP requestModerate - YAML with placeholder syntaxRequires understanding YAML custom tags
AI flexibilityThe model can improvise URL constructionThe model fills in declared fieldsThe model fills in typed field nodes
ValidationNo built-in input validationFields have required/optional markersFull type system with defaults, enums, transforms
Response shapingReturns the full response bodyCan use options.format to control outputCan use options.format to control output
AuthenticationManual header constructionSecret references with ${SECRET_DEFAULT}Secret references with !reference tag
Dynamic compositionNot supportedLimited to placeholder substitution!concat for building strings from parts
Best forQuick prototypes, simple public APIsProduction APIs, authenticated endpointsComplex APIs, template libraries, programmatic use

As a general rule, the simple format is great for getting started quickly, the structured format is better for production use, and the YAML tags format is ideal when you need full type safety, field validation, transforms, and dynamic string composition.

Authentication with Secrets

Most real-world APIs require authentication. ChatBotKit uses secrets to manage API keys, tokens, and OAuth credentials securely. Secrets are never exposed in the ability instruction or in conversation logs.

How Secrets Work

  1. You create a secret in ChatBotKit that stores your API credentials.
  2. You link the secret to your ability (or skillset).
  3. In the ability instruction, you reference the secret with ${SECRET_DEFAULT} or ${SECRET_NAME}.
  4. At execution time, ChatBotKit replaces the placeholder with the actual secret value, formatted according to its type.

Secret Types

TypeHow it authenticatesExample use case
BearerAdds Bearer <token> to the header valueMost REST APIs (OpenAI, Stripe, etc.)
PlainUses the raw value without transformationAPIs that expect a key in a query parameter
BasicBase64-encodes username:password with Basic prefixLegacy HTTP Basic Auth APIs
OAuthManages a full OAuth 2.0 token flow with automatic refreshGoogle, Slack, GitHub OAuth apps

Step-by-Step: Adding a Bearer Token Secret

  1. Navigate to Secrets in your ChatBotKit dashboard.
  2. Click Create Secret.
  3. Choose the Bearer type.
  4. Paste your API token into the value field.
  5. Save the secret - note the secret ID.

Then, in your ability:

When the ability runs, ${SECRET_DEFAULT} is replaced with Bearer your-api-token-here. You do not need to type the Bearer prefix yourself - ChatBotKit adds it automatically for bearer-type secrets.

Step-by-Step: Using a Plain API Key

Some APIs expect the key as a query parameter rather than a header. In that case, use a plain secret:

For a plain secret, ChatBotKit inserts the raw key value without any prefix.

Named Secrets

If your ability needs multiple credentials (for example, an API key and a separate webhook secret), you can use named secrets instead of the default:

Each ${SECRET_NAME} placeholder is resolved independently. The SECRET_DEFAULT refers to the primary secret linked to the ability, while any other name (like SECRET_WEBHOOK) refers to a secret with that name in your account.

Admin-Managed vs User-Authenticated Secrets

ChatBotKit supports two models for secret ownership, depending on who provides and manages the credentials.

Admin-Managed Secrets (Shared)

With shared secrets, the administrator provides the API key or token once, and every user of the bot benefits from it. This is the most common model for company-internal bots.

How it works:

  1. The admin creates a secret in the ChatBotKit dashboard.
  2. The admin links the secret to the ability or skillset.
  3. All conversations automatically use the admin's credentials.

Use cases:

  • Internal tools where the company owns the API subscription
  • Bots that query public APIs with a single API key
  • Team-shared bots with centralized billing

User-Authenticated Secrets (Personal)

With personal secrets, each end user authenticates individually. This is typically used for OAuth integrations where the bot needs to access user-specific data.

How it works:

  1. The admin configures an OAuth secret with the client ID, client secret, authorization URL, and token URL.
  2. When a user interacts with the bot and triggers the ability, they are prompted to authorize access through the OAuth flow.
  3. Each user's token is stored separately and used only for their conversations.

Use cases:

  • Accessing a user's Google Calendar or Gmail
  • Reading a user's Slack messages
  • Managing a user's GitHub repositories

Example: Google Calendar OAuth Ability

First, create an OAuth secret for Google Calendar with the following configuration:

FieldValue
TypeOAuth
Client IDYour Google OAuth client ID
Client SecretYour Google OAuth client secret
Authorization URLhttps://accounts.google.com/o/oauth2/auth?access_type=offline&prompt=consent
Token URLhttps://accounts.google.com/o/oauth2/token
Scopehttps://www.googleapis.com/auth/calendar.readonly

Then, create an ability that uses this secret:

When a user triggers this ability for the first time, they will be guided through the Google OAuth consent screen. After authorization, the bot can fetch their calendar events.

Putting It All Together

Let's build a complete example - a bot that fetches cryptocurrency prices from an API that requires an API key.

Step 1: Create the Secret

  1. Go to Secrets in the ChatBotKit dashboard.
  2. Create a new Plain secret.
  3. Paste your CoinAPI key.
  4. Name it appropriately (e.g., "CoinAPI Key").

Step 2: Create the Skillset and Ability

  1. Create a new Skillset named "Cryptocurrency".
  2. Add an ability named get_crypto_price with the description: "Get the current price of a cryptocurrency."
  3. Link the secret you created in Step 1 to this ability.
  4. Set the instruction to:

Or equivalently, using the YAML tags format:

Step 3: Connect and Test

  1. Attach the Cryptocurrency skillset to your bot.
  2. Open the bot in the playground.
  3. Ask: "What is the current price of Bitcoin?"

The bot will call the CoinAPI endpoint, extract the exchange rate, and respond with the formatted result.

Troubleshooting

Ability does not execute the fetch request

  • Verify the instruction is a valid YAML document inside the fetch code block.
  • Check that required fields are marked with ! (e.g., ((query! ys|...))).
  • Ensure the bot's model supports function/tool calling.

Authentication errors (401 or 403)

  • Confirm the secret is linked to the ability.
  • Check the secret type matches the API's expected format (Bearer, Plain, etc.).
  • For OAuth secrets, verify the scopes include the permissions the API requires.

Empty or unexpected responses

  • Test the API URL directly in a browser or with curl to confirm it returns data.
  • Try removing the options block temporarily to see the full raw response.

Next Steps