dynamic-api-integration

Mode: Cognitive/Prompt-Driven — No standalone utility script; use via agent context.

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "dynamic-api-integration" with this command: npx skills add oimiragieo/agent-studio/oimiragieo-agent-studio-dynamic-api-integration

Mode: Cognitive/Prompt-Driven — No standalone utility script; use via agent context.

Dynamic API Integration

Overview

This skill teaches agents how to dynamically discover, parse, and call external HTTP APIs at runtime. It is adapted from the Universal Tool Calling Protocol (UTCP) patterns, translated into Node.js / Claude Code tool patterns.

Core workflow (5-phase, inspired by UTCP agent state machine):

  • Discover — Fetch and parse an OpenAPI/Swagger spec (or define a manual tool template).

  • Match — Map the user's intent to the right API endpoint semantically.

  • Construct — Build the HTTP request with proper method, path, params, headers, body, and auth.

  • Execute — Call the API via Bash (curl) or WebFetch and capture the response.

  • Chain — If the task is not yet complete, re-analyze and execute another call (up to max_iterations).

When to Use

Use this skill when:

  • Agent needs to call an external REST API it has not used before

  • User provides an API URL or OpenAPI spec URL and wants data extracted

  • Agent must discover available endpoints from a spec before choosing which to call

  • Multiple API calls need to be chained iteratively (search -> get details -> filter)

  • Agent needs to construct HTTP requests with authentication and parameters

Do NOT use when:

  • The API is already wrapped as an MCP tool (use the MCP tool directly)

  • The integration is a one-time hardcoded call (just use Bash curl directly)

  • The API requires OAuth 2.0 authorization code flow with user-interactive redirect

  • The API uses WebSocket or streaming-only protocols (not HTTP REST)

Iron Laws

  • NEVER hardcode API keys, tokens, or secrets in requests, curl commands, or source files — always use environment variables ($ENV_VAR ) or a secrets manager.

  • ALWAYS discover the API spec (OpenAPI/Swagger) before writing any integration code — guessing endpoint shapes without spec evidence produces broken integrations.

  • NEVER skip pagination handling when the API returns list responses — assuming single-page results silently drops data for any dataset above the page limit.

  • ALWAYS implement retry logic with exponential backoff for transient failures (429, 503) — dynamic APIs are unreliable by nature and integrations without retries fail under normal production conditions.

  • NEVER trust API responses without validating the schema of each response before use — dynamic API shapes change without notice; unvalidated responses cause runtime crashes in callers.

Phase 1: Discover — Fetch and Parse the API Spec

Option A: OpenAPI/Swagger Spec Discovery

When the API provides an OpenAPI spec (most modern APIs do):

Step 1: Fetch the OpenAPI spec

WebFetch({ url: "https://api.example.com/openapi.json", prompt: "Extract all API endpoints. For each endpoint, list: HTTP method, path, description, required parameters, optional parameters, authentication requirement. Return as a structured list." })

What to extract from the spec:

Field Location in Spec Purpose

Base URL servers[0].url

API root for all requests

Endpoints paths.*

Available operations

Methods paths.*.get/post/put/delete

HTTP verbs per endpoint

Parameters paths...parameters[]

Query, path, header params

Request body paths...requestBody

POST/PUT payload schema

Auth components.securitySchemes

API key, Bearer, OAuth

Response schema paths...responses.200

Expected response format

Common OpenAPI spec locations:

Option B: Manual Tool Template (No Spec Available)

When no OpenAPI spec exists, define a tool template manually:

{ "name": "search_books", "description": "Search Open Library for books by query", "base_url": "https://openlibrary.org/search.json", "method": "GET", "auth": null, "parameters": { "q": { "type": "string", "required": true, "in": "query", "description": "Search query (title, author, ISBN)" }, "limit": { "type": "integer", "required": false, "in": "query", "description": "Max results to return (default 10)" }, "page": { "type": "integer", "required": false, "in": "query", "description": "Page number for pagination" } }, "response_hint": "Returns { numFound, docs: [{ title, author_name, first_publish_year }] }" }

Tool Template JSON Schema

The tool template format (inspired by UTCP manual_call_templates ):

{ "name": "string (required) — unique tool identifier, lowercase_snake_case", "description": "string (required) — what this tool does, used for semantic matching", "base_url": "string (required) — full URL including path", "method": "string (required) — GET | POST | PUT | PATCH | DELETE", "content_type": "string (optional) — default: application/json", "auth": { "type": "string — api_key | bearer | basic | none", "header": "string — header name (e.g., X-Api-Key, Authorization)", "env_var": "string — environment variable name holding the secret", "prefix": "string (optional) — e.g., 'Bearer ' for bearer auth" }, "parameters": { "<param_name>": { "type": "string | integer | boolean | array | object", "required": "boolean", "in": "query | path | header | body", "description": "string — what this parameter does", "default": "any (optional) — default value if not provided" } }, "response_hint": "string (optional) — brief description of response shape" }

Phase 2: Match — Semantic Intent-to-Endpoint Mapping

Before calling an API, match the user's intent to the correct endpoint:

Step 1: Understand the user's goal

Ask yourself: What data does the user want? What action do they want performed?

Step 2: Map intent to endpoint

User Intent Likely HTTP Method Endpoint Pattern

"Find / search / list / get" GET /search , /list , /{resource}

"Create / add / register" POST /{resource}

"Update / modify / change" PUT or PATCH /{resource}/{id}

"Delete / remove" DELETE /{resource}/{id}

"Get details about X" GET /{resource}/{id}

Step 3: Select parameters

  • Required parameters: Must be provided (check required: true in spec/template).

  • Optional parameters: Use only if user specified them or they improve results.

  • Path parameters: Substitute into URL (e.g., /repos/{owner}/{repo} ).

  • Query parameters: Append as ?key=value&key2=value2 .

  • Body parameters: Send as JSON payload in POST/PUT/PATCH.

Phase 3: Construct — Build the HTTP Request

Request Construction Checklist

  • URL: Base URL + path + path parameter substitution

  • Method: GET, POST, PUT, PATCH, DELETE

  • Headers: Content-Type, Authorization, Accept, custom headers

  • Query parameters: URL-encoded, appended to URL

  • Body: JSON payload for POST/PUT/PATCH

  • Auth: Injected from environment variable

Auth Patterns

API Key (Header):

curl -s -X GET "https://api.example.com/data?q=test"
-H "X-Api-Key: $API_KEY"

Bearer Token:

curl -s -X GET "https://api.example.com/data"
-H "Authorization: Bearer $AUTH_TOKEN"

Basic Auth:

curl -s -X GET "https://api.example.com/data"
-u "$USERNAME:$PASSWORD"

No Auth (Public API):

curl -s -X GET "https://api.example.com/data?q=test"

Request Templates by Method

GET with query parameters:

curl -s -X GET "https://api.example.com/search?q=test&#x26;limit=10&#x26;page=1"
-H "Accept: application/json"
-H "Authorization: Bearer $TOKEN"

POST with JSON body:

curl -s -X POST "https://api.example.com/items"
-H "Content-Type: application/json"
-H "Authorization: Bearer $TOKEN"
-d '{"name": "New Item", "category": "tools", "price": 29.99}'

PUT with path parameter:

curl -s -X PUT "https://api.example.com/items/123"
-H "Content-Type: application/json"
-H "Authorization: Bearer $TOKEN"
-d '{"name": "Updated Item", "price": 39.99}'

DELETE:

curl -s -X DELETE "https://api.example.com/items/123"
-H "Authorization: Bearer $TOKEN"

Phase 4: Execute — Call the API and Process the Response

Using Bash (curl) — Primary Method

Execute and capture response + HTTP status

RESPONSE=$(curl -s -w "\n%{http_code}" -X GET "https://api.example.com/search?q=test"
-H "Accept: application/json") HTTP_CODE=$(echo "$RESPONSE" | tail -1) BODY=$(echo "$RESPONSE" | sed '$d')

echo "Status: $HTTP_CODE" echo "Body: $BODY" | head -c 2000 # Truncate to 2KB for context safety

Using WebFetch — When You Need AI Processing

WebFetch({ url: 'https://api.example.com/search?q=test', prompt: 'Extract the top 5 results with their titles and descriptions. Format as a numbered list.', });

When to use which:

Scenario Tool Reason

Need raw JSON for further processing Bash (curl) Full control, parseable output

Need summarized/extracted data WebFetch AI processes response inline

Need to check HTTP status codes Bash (curl) WebFetch abstracts status away

Large response (>50KB) Bash (curl) + truncate WebFetch may timeout on large pages

HTML page (not JSON) WebFetch Converts HTML to markdown

Error Handling

HTTP Status Code Handling:

Status Meaning Action

200-299 Success Parse response, continue

400 Bad Request Check parameters, fix and retry

401 Unauthorized Check API key/token, re-authenticate

403 Forbidden Check permissions, report to user

404 Not Found Check URL/resource ID, try alternative endpoint

429 Rate Limited Wait (check Retry-After header), then retry

500-599 Server Error Wait and retry up to 3 times

Retry with Exponential Backoff:

Retry pattern for transient errors (429, 5xx)

for attempt in 1 2 3; do RESPONSE=$(curl -s -w "\n%{http_code}" -X GET "$URL" -H "Authorization: Bearer $TOKEN") HTTP_CODE=$(echo "$RESPONSE" | tail -1) if [ "$HTTP_CODE" -lt 400 ]; then break # Success fi echo "Attempt $attempt failed ($HTTP_CODE), retrying in $((attempt * 2))s..." sleep $((attempt * 2)) done

Response Processing

Parse JSON response (Bash):

Extract specific fields from JSON response

echo "$BODY" | node -e " const data = JSON.parse(require('fs').readFileSync('/dev/stdin', 'utf8')); console.log('Total:', data.totalResults); data.items?.slice(0, 5).forEach((item, i) => { console.log(`${i+1}. ${item.title} — ${item.description?.substring(0, 80)}`); }); "

Truncate large responses:

Safety: never pass >10KB of API response into context

BODY_TRUNCATED=$(echo "$BODY" | head -c 10000) if [ ${#BODY} -gt 10000 ]; then echo "[TRUNCATED: Response was $(echo "$BODY" | wc -c) bytes, showing first 10KB]" fi

Phase 5: Chain — Iterative Multi-Call Workflow

Many tasks require multiple API calls chained together. Use the UTCP-inspired iterative pattern:

Chaining Pattern

Iteration 1: Search -> Get list of results Iteration 2: Get details for top result Iteration 3: Perform action on result (max_iterations guard: stop at 5)

The Iteration Guard (MANDATORY)

MAX_ITERATIONS = 5

Before each API call: IF iteration_count >= MAX_ITERATIONS: STOP. Summarize what was gathered so far and respond. ELSE: Execute the call, increment counter, re-analyze task.

Why this matters: Without an iteration guard, an agent could loop indefinitely calling APIs. UTCP uses a default of 3; we recommend 5 for more complex multi-step workflows.

Chaining Examples

Example 1: Search and Get Details

User: "Find information about the book '1984' by George Orwell"

Iteration 1: Call: GET https://openlibrary.org/search.json?q=1984+george+orwell&#x26;limit=5 Result: Found 5 matches, top result has key "/works/OL1168083W"

Iteration 2: Call: GET https://openlibrary.org/works/OL1168083W.json Result: Full book details (title, description, subjects, covers)

Task complete: Return summarized book information.

Example 2: GitHub — Find and Analyze a Repository

User: "What are the most recent issues in the react repository?"

Iteration 1: Call: GET https://api.github.com/repos/facebook/react/issues?state=open&#x26;per_page=10&#x26;sort=created Headers: Authorization: Bearer $GITHUB_TOKEN Result: 10 most recent open issues

Task complete: Summarize issue titles, labels, and dates.

Example 3: Multi-API Chain

User: "Find news about AI safety and summarize the top article"

Iteration 1: Call: GET https://newsapi.org/v2/everything?q=AI+safety&#x26;sortBy=publishedAt&#x26;pageSize=5 Headers: X-Api-Key: $NEWS_API_KEY Result: 5 articles with titles, URLs

Iteration 2: Call: WebFetch({ url: articles[0].url, prompt: "Summarize this article in 3 bullet points" }) Result: Article summary

Task complete: Return article title + summary.

Real-World API Examples

GitHub API (Bearer Token Auth)

List repositories for a user

curl -s -X GET "https://api.github.com/users/octocat/repos?sort=updated&#x26;per_page=5"
-H "Accept: application/vnd.github+json"
-H "Authorization: Bearer $GITHUB_TOKEN"

Tool Template:

{ "name": "github_list_repos", "description": "List repositories for a GitHub user, sorted by most recently updated", "base_url": "https://api.github.com/users/{username}/repos", "method": "GET", "auth": { "type": "bearer", "header": "Authorization", "env_var": "GITHUB_TOKEN", "prefix": "Bearer " }, "parameters": { "username": { "type": "string", "required": true, "in": "path", "description": "GitHub username" }, "sort": { "type": "string", "required": false, "in": "query", "description": "Sort field: created, updated, pushed, full_name", "default": "updated" }, "per_page": { "type": "integer", "required": false, "in": "query", "description": "Results per page (max 100)", "default": 10 } } }

Open Library API (No Auth)

Search for books

curl -s -X GET "https://openlibrary.org/search.json?q=george+orwell&#x26;limit=5"
-H "Accept: application/json"

JSONPlaceholder (Testing/Prototyping)

GET all posts

curl -s https://jsonplaceholder.typicode.com/posts?_limit=5

POST new item

curl -s -X POST https://jsonplaceholder.typicode.com/posts
-H "Content-Type: application/json"
-d '{"title": "Test Post", "body": "Hello world", "userId": 1}'

Weather API (API Key Auth)

Get current weather

curl -s "https://api.open-meteo.com/v1/forecast?latitude=51.5074&#x26;longitude=-0.1278&#x26;current_weather=true"

Context Management for Large Responses

API responses can be very large. Apply these rules to prevent context overflow:

Response Size Limits

Response Size Action

< 5 KB Use full response

5-20 KB Extract relevant fields only

20-50 KB Summarize via WebFetch or node script

50 KB Truncate to first 5KB + count remaining

Extraction Pattern (Recommended for Large Responses)

Instead of dumping full response, extract what you need

curl -s "https://api.example.com/search?q=test" | node -e " const data = JSON.parse(require('fs').readFileSync('/dev/stdin', 'utf8')); // Extract only what the user asked for const results = data.results.slice(0, 5).map(r => ({ id: r.id, title: r.title, summary: r.description?.substring(0, 200) })); console.log(JSON.stringify(results, null, 2)); "

Security Checklist

  • All API keys stored in environment variables (never in code/commands)

  • HTTPS used for all API calls (never HTTP for authenticated requests)

  • Response data validated before use (check status codes)

  • No user secrets logged or written to files

  • Rate limits respected (check headers: X-RateLimit-Remaining)

  • Sensitive response data (PII, tokens) not stored in memory files

  • Timeout set on all requests (curl --max-time 30 )

Verification Checklist

Before completing a dynamic API integration task:

  • API spec was fetched and endpoints were identified

  • User intent was mapped to the correct endpoint and method

  • Request includes proper authentication (if required)

  • Request parameters match the API schema (required params present)

  • HTTP status code was checked and errors handled

  • Response was truncated/summarized if > 5KB

  • Iteration count did not exceed max_iterations (5)

  • No API keys were hardcoded in any command or file

Anti-Patterns (AVOID)

Anti-Pattern Why It Fails Correct Approach

Hardcoding API keys Security risk, breaks when rotated Use $ENV_VAR in all commands

Calling API without reading spec first Wrong endpoint, wrong parameters Discover first (Phase 1)

Passing full 100KB response to context Context overflow, degraded performance Truncate/extract (Phase 4)

No iteration guard on chained calls Infinite loops burning tokens Always enforce max_iterations

Guessing parameter names 400 errors, wasted calls Read spec/docs before constructing

Ignoring HTTP error codes Silent failures, wrong results Check status, handle 4xx/5xx

Using POST when GET is correct API rejects or creates unintended resources Match method to intent (Phase 2)

Quick Reference Card

DISCOVER → WebFetch(spec_url) or define manual tool template MATCH → Map user intent to endpoint + method + params CONSTRUCT → Build curl command with URL, headers, auth, body EXECUTE → Bash(curl) for JSON, WebFetch for HTML/summarize CHAIN → Re-analyze task, call again (max 5 iterations)

Auth Quick Reference:

API Key: -H "X-Api-Key: $KEY" Bearer: -H "Authorization: Bearer $TOKEN" Basic: -u "$USER:$PASS" None: (no auth header needed)

Tool Template Quick Create:

{ "name": "...", "description": "...", "base_url": "...", "method": "GET", "auth": { "type": "api_key", "header": "...", "env_var": "..." }, "parameters": { "q": { "type": "string", "required": true, "in": "query" } } }

Research Basis

This skill is adapted from:

  • Universal Tool Calling Protocol (UTCP) — open standard for AI agent tool calling

  • UTCP Agent — LangGraph-based reference implementation

  • UTCP Specification — RFC and protocol definition

  • OpenAPI Specification 3.1 — API description standard

  • OpenAPI Best Practices — community guidelines

  • agents.json Specification — API-agent contract standard

  • API Integration Patterns (2026) — pattern taxonomy

Related Skills

  • auth-security-expert — OAuth 2.1, JWT, encryption patterns

  • nodejs-expert — Node.js HTTP patterns

  • debugging — API call failure investigation

  • research-synthesis — Researching new APIs before integration

Memory Protocol

Before starting: Read .claude/context/memory/learnings.md

After completing:

  • New API pattern discovered -> .claude/context/memory/learnings.md

  • API issue/limitation found -> .claude/context/memory/issues.md

  • API design decision made -> .claude/context/memory/decisions.md

  • Reusable tool template created -> save to .claude/context/memory/named/api-templates.md

Assume interruption: if it is not in memory, it did not happen.

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Automation

filesystem

No summary provided by upstream source.

Repository SourceNeeds Review
Automation

slack-notifications

No summary provided by upstream source.

Repository SourceNeeds Review
Automation

chrome-browser

No summary provided by upstream source.

Repository SourceNeeds Review