<!--
hoody-curl Subskill (sdk)
Auto-generated by Hoody Skills Generator
Generated: 2026-05-06T20:05:44.440Z
Model: mimo-v2.5-pro
Mode: sdk


Tokens: 8742

DO NOT EDIT MANUALLY - Changes will be overwritten on next generation
-->

# hoody-curl Subskill

## Overview

**hoody-curl** is a universal HTTP proxy service that GET-ifies any REST API for universal access. It wraps complex API calls behind simple, standardized URLs, enabling any client—including those with limited HTTP method support—to interact with external services.

### When to Use hoody-curl

- **API Simplification**: Convert complex POST/PUT/DELETE operations into simple GET requests with query parameters.
- **Scheduled Requests**: Create cron-based recurring HTTP requests that survive server restarts.
- **Async Jobs**: Submit long-running HTTP requests as background jobs with progress tracking.
- **Session Management**: Maintain cookie-based sessions across multiple requests for authentication flows.
- **File Storage**: Automatically save HTTP response bodies to organized storage.
- **Real-time Monitoring**: Subscribe to job lifecycle events via WebSocket.
- **Metrics & Health**: Export Prometheus metrics and check service health.

### How It Fits the Hoody Philosophy

hoody-curl embodies the "GET-ify any REST API for universal access" principle. By proxying complex API interactions through a unified interface, it democratizes access to external services. Any client capable of making HTTP GET requests can leverage the full power of external APIs through hoody-curl.

### Service Access Pattern

All hoody-curl endpoints are accessed through the Hoody Kit service URL pattern:

```
https://{projectId}-{containerId}-curl-{serviceId}.{node}.containers.hoody.icu
```

Authentication is handled automatically by the Hoody Proxy routing system. Use the Hoody SDK client for all interactions.

---

## Common Workflows

### Workflow 1: Simple HTTP Request via GET

Execute a basic HTTP request using query parameters—ideal for quick testing and simple GET requests.

```
import { HoodyClient } from '@hoody-ai/hoody-sdk'

const client = new HoodyClient({ baseURL: 'https://api.hoody.icu', token: 'YOUR_TOKEN' })

// Execute a simple GET request
const response = await client.curl.executeCurlRequestGet(
  'https://api.example.com/data',
  'GET',
  'json',
  'sync'
)

console.log(response)
```

### Workflow 2: Advanced HTTP Request with Full Configuration

Use the POST endpoint for comprehensive cURL capabilities including custom headers, authentication, and async mode.

```
import { HoodyClient } from '@hoody-ai/hoody-sdk'

const client = new HoodyClient({ baseURL: 'https://api.hoody.icu', token: 'YOUR_TOKEN' })

// Execute an advanced HTTP request
const response = await client.curl.execute({
  url: 'https://api.example.com/protected-resource',
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': 'Bearer external-api-token'
  },
  body: JSON.stringify({ key: 'value' }),
  mode: 'async',
  job_name: 'data-fetch-job',
  follow_redirects: true,
  timeout: 30
})

console.log(response)
```

### Workflow 3: Async Job Management

Submit long-running requests as background jobs and monitor their progress.

```
import { HoodyClient } from '@hoody-ai/hoody-sdk'

const client = new HoodyClient({ baseURL: 'https://api.hoody.icu', token: 'YOUR_TOKEN' })

// Step 1: Submit an async job
const jobResponse = await client.curl.execute({
  url: 'https://api.example.com/large-dataset',
  method: 'GET',
  mode: 'async',
  job_name: 'large-data-fetch'
})

const jobId = jobResponse.job_id
console.log(`Job submitted: ${jobId}`)

// Step 2: Check job status
const jobDetails = await client.curl.jobs.get(jobId)
console.log(`Job status: ${jobDetails.status}`)

// Step 3: Retrieve result when completed
if (jobDetails.status === 'completed') {
  const result = await client.curl.jobs.getResult(jobId)
  console.log('Job result:', result)
}
```

### Workflow 4: List and Manage All Jobs

Retrieve and manage all async jobs with pagination support.

```
import { HoodyClient } from '@hoody-ai/hoody-sdk'

const client = new HoodyClient({ baseURL: 'https://api.hoody.icu', token: 'YOUR_TOKEN' })

// List all jobs (first page)
const jobs = await client.curl.jobs.list(1, 20)
console.log(`Total jobs: ${jobs.total}`)

// List all jobs across all pages
const allJobs = await client.curl.jobs.listAll()
console.log(`All jobs collected: ${allJobs.length}`)

// Iterate through jobs asynchronously
for await (const page of client.curl.jobs.listIterator()) {
  for (const job of page.items) {
    console.log(`Job ${job.id}: ${job.status}`)
  }
}

// Cancel a specific job
await client.curl.jobs.cancel({ id: 'job-id-to-cancel' })
```

### Workflow 5: Create and Manage Scheduled Requests

Set up cron-based recurring HTTP requests that persist across server restarts.

```
import { HoodyClient } from '@hoody-ai/hoody-sdk'

const client = new HoodyClient({ baseURL: 'https://api.hoody.icu', token: 'YOUR_TOKEN' })

// Step 1: Create a scheduled job (runs every hour)
const schedule = await client.curl.schedules.create({
  cron: '0 0 * * * *',
  request: {
    url: 'https://api.example.com/health-check',
    method: 'GET'
  }
})

console.log(`Schedule created: ${schedule.id}`)

// Step 2: List all schedules
const schedules = await client.curl.schedules.list()
console.log(`Total schedules: ${schedules.total}`)

// Step 3: Get schedule details
const scheduleDetails = await client.curl.schedules.get(schedule.id)
console.log(`Next execution: ${scheduleDetails.next_execution}`)

// Step 4: Toggle schedule (disable without deleting)
await client.curl.schedules.toggle(schedule.id, { enabled: false })

// Step 5: Delete schedule when no longer needed
await client.curl.schedules.delete(schedule.id)
```

### Workflow 6: Cookie Session Management

Maintain stateful HTTP interactions by preserving cookies across multiple requests.

```
import { HoodyClient } from '@hoody-ai/hoody-sdk'

const client = new HoodyClient({ baseURL: 'https://api.hoody.icu', token: 'YOUR_TOKEN' })

// Step 1: Execute request that creates a session (cookies auto-saved)
const loginResponse = await client.curl.execute({
  url: 'https://example.com/login',
  method: 'POST',
  body: JSON.stringify({ username: 'user', password: 'pass' }),
  session_id: 'my-auth-session'
})

// Step 2: List all sessions
const sessions = await client.curl.sessions.list()
console.log(`Active sessions: ${sessions.total}`)

// Step 3: Get session details
const sessionDetails = await client.curl.sessions.get({ id: 'my-auth-session' })
console.log(`Session cookies: ${sessionDetails.cookies.length}`)

// Step 4: Get cookies only (without metadata)
const cookies = await client.curl.sessions.getCookies({ id: 'my-auth-session' })
console.log('Cookies:', cookies)

// Step 5: Use session for authenticated requests
const protectedData = await client.curl.execute({
  url: 'https://example.com/api/protected',
  method: 'GET',
  session_id: 'my-auth-session'
})

// Step 6: Delete session when done
await client.curl.sessions.delete({ id: 'my-auth-session' })
```

### Workflow 7: File Storage Operations

Access files saved from HTTP responses, organized by job, domain, and date.

```
import { HoodyClient } from '@hoody-ai/hoody-sdk'

const client = new HoodyClient({ baseURL: 'https://api.hoody.icu', token: 'YOUR_TOKEN' })

// Step 1: Execute request with file saving enabled
await client.curl.execute({
  url: 'https://example.com/files/report.pdf',
  method: 'GET',
  save: true,
  save_path: 'reports/monthly-report.pdf'
})

// Step 2: List all saved files
const files = await client.curl.storage.list()
console.log(`Total files: ${files.total}`)

// Step 3: Download a saved file
const fileContent = await client.curl.storage.getFile({ path: 'reports/monthly-report.pdf' })

// Step 4: Delete a file
await client.curl.storage.deleteFile({ path: 'reports/monthly-report.pdf' })
```

### Workflow 8: Real-time Job Event Monitoring

Subscribe to job lifecycle events via WebSocket for real-time progress tracking.

```
import { HoodyClient } from '@hoody-ai/hoody-sdk'

const client = new HoodyClient({ baseURL: 'https://api.hoody.icu', token: 'YOUR_TOKEN' })

// Subscribe to all job events
client.curl.events.streamWs()

// Or subscribe to specific job events
client.curl.events.streamWs('specific-job-id')
```

**WebSocket Message Types:**
- `jobstarted` — `{ job_id, name }`
- `jobprogress` — `{ job_id, progress }` (progress is 0.0 to 1.0)
- `jobcompleted` — `{ job_id, result }`
- `jobfailed` — `{ job_id, error }`

---

## Advanced Operations

### Multi-Step Workflow: Authenticated API Scraping with Storage

Combine sessions, async jobs, and storage for complex data extraction workflows.

```
import { HoodyClient } from '@hoody-ai/hoody-sdk'

const client = new HoodyClient({ baseURL: 'https://api.hoody.icu', token: 'YOUR_TOKEN' })

// Step 1: Authenticate and create session
await client.curl.execute({
  url: 'https://target-site.com/auth',
  method: 'POST',
  body: JSON.stringify({ credentials: '...' }),
  session_id: 'scraping-session'
})

// Step 2: Submit async job to scrape data with session
const job = await client.curl.execute({
  url: 'https://target-site.com/api/data',
  method: 'GET',
  session_id: 'scraping-session',
  mode: 'async',
  job_name: 'data-scrape',
  save: true,
  save_path: 'scrapes/data-export.json'
})

// Step 3: Monitor job progress
let jobStatus = 'pending'
while (jobStatus !== 'completed' && jobStatus !== 'failed') {
  const details = await client.curl.jobs.get(job.job_id)
  jobStatus = details.status
  console.log(`Progress: ${details.progress || 0}%`)
  await new Promise(resolve => setTimeout(resolve, 2000))
}

// Step 4: Retrieve stored file
if (jobStatus === 'completed') {
  const data = await client.curl.storage.getFile({ path: 'scrapes/data-export.json' })
  console.log('Scraped data:', data)
}

// Step 5: Cleanup
await client.curl.sessions.delete({ id: 'scraping-session' })
```

### Error Recovery Pattern

Handle job failures gracefully with retry logic.

```
import { HoodyClient } from '@hoody-ai/hoody-sdk'

const client = new HoodyClient({ baseURL: 'https://api.hoody.icu', token: 'YOUR_TOKEN' })

async function executeWithRetry(requestConfig: any, maxRetries = 3) {
  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      const response = await client.curl.execute(requestConfig)
      
      if (requestConfig.mode === 'async') {
        // Poll for completion
        const jobId = response.job_id
        let status = 'pending'
        
        while (status === 'pending' || status === 'running') {
          const job = await client.curl.jobs.get(jobId)
          status = job.status
          
          if (status === 'failed') {
            throw new Error(`Job failed: ${job.error}`)
          }
          
          await new Promise(resolve => setTimeout(resolve, 1000))
        }
        
        return await client.curl.jobs.getResult(jobId)
      }
      
      return response
    } catch (error) {
      console.error(`Attempt ${attempt} failed:`, error)
      if (attempt === maxRetries) throw error
      await new Promise(resolve => setTimeout(resolve, 1000 * attempt))
    }
  }
}

// Usage
const result = await executeWithRetry({
  url: 'https://api.example.com/flaky-endpoint',
  method: 'GET',
  mode: 'async',
  timeout: 60
})
```

### Performance Considerations

1. **Use Async Mode for Long Requests**: Set `mode: 'async'` for requests that may take longer than 30 seconds to avoid timeouts.

2. **Pagination for Large Lists**: Use `listAll()` or `listIterator()` methods for collecting all items across multiple pages.

3. **Session Reuse**: Create sessions once and reuse them across multiple requests to avoid repeated authentication overhead.

4. **Storage Organization**: Use meaningful `save_path` values organized by domain or date for easier file management.

5. **Schedule Management**: Toggle schedules instead of deleting/recreating them to preserve execution history.

### Health Check and Monitoring

```
import { HoodyClient } from '@hoody-ai/hoody-sdk'

const client = new HoodyClient({ baseURL: 'https://api.hoody.icu', token: 'YOUR_TOKEN' })

// Check service health (unauthenticated)
const health = await client.curl.health.check()
console.log('Service status:', health.status)

// Get Prometheus metrics
const metrics = await client.curl.ops.metrics()
console.log('Metrics:', metrics)
```

---

## Quick Reference

### Most Common Endpoints

| Operation | SDK Method | HTTP Method & Path |
|-----------|------------|-------------------|
| Health Check | `client.curl.health.check()` | `GET /api/v1/curl/health` |
| Execute Request (GET) | `client.curl.executeCurlRequestGet(url)` | `GET /api/v1/curl/request` |
| Execute Request (POST) | `client.curl.execute(data)` | `POST /api/v1/curl/request` |
| List Jobs | `client.curl.jobs.list()` | `GET /api/v1/curl/jobs` |
| Get Job | `client.curl.jobs.get(id)` | `GET /api/v1/curl/jobs/{id}` |
| Get Job Result | `client.curl.jobs.getResult(id)` | `GET /api/v1/curl/jobs/{id}/result` |
| Cancel Job | `client.curl.jobs.cancel(id)` | `DELETE /api/v1/curl/jobs/{id}` |
| List Schedules | `client.curl.schedules.list()` | `GET /api/v1/curl/schedule` |
| Create Schedule | `client.curl.schedules.create(data)` | `POST /api/v1/curl/schedule` |
| Toggle Schedule | `client.curl.schedules.toggle(id, data)` | `PATCH /api/v1/curl/schedule/{id}/toggle` |
| List Sessions | `client.curl.sessions.list()` | `GET /api/v1/curl/sessions` |
| Get Session Cookies | `client.curl.sessions.getCookies(id)` | `GET /api/v1/curl/sessions/{id}/cookies` |
| List Storage Files | `client.curl.storage.list()` | `GET /api/v1/curl/storage` |
| Download File | `client.curl.storage.getFile(path)` | `GET /api/v1/curl/storage/{path}` |
| Stream Events | `client.curl.events.streamWs()` | `GET /api/v1/curl/ws` |
| Prometheus Metrics | `client.curl.ops.metrics()` | `GET /metrics` |

### Essential Parameters

**Request Execution:**
- `url` (required): Target URL to request
- `method`: HTTP method (GET, POST, PUT, DELETE, PATCH)
- `headers`: Custom HTTP headers object
- `body`: Request body (string or JSON)
- `mode`: `'sync'` (immediate) or `'async'` (background job)
- `session_id`: Cookie session identifier for stateful requests
- `save`: Boolean to save response to storage
- `save_path`: Storage path for saved files
- `timeout`: Request timeout in seconds

**Schedule Creation:**
- `cron` (required): 6-field cron expression (`second minute hour day month weekday`)
- `request` (required): Object containing `url` and other request parameters

**Job Management:**
- `id` (required): Job identifier string
- `page`: Page number for pagination
- `limit`: Items per page

### Typical Response Formats

**Health Check Response:**
```
{
  "status": "healthy",
  "service": "hoody-curl",
  "version": "1.0.0",
  "uptime": 86400,
  "timestamp": "2025-01-15T10:30:00Z"
}
```

**Job Response:**
```
{
  "id": "job-abc123",
  "status": "completed",
  "created_at": "2025-01-15T10:00:00Z",
  "completed_at": "2025-01-15T10:00:05Z",
  "request": {
    "url": "https://api.example.com/data",
    "method": "GET"
  },
  "response": {
    "status_code": 200,
    "headers": {},
    "body": {}
  }
}
```

**Paginated List Response:**
```
{
  "items": [],
  "total": 42,
  "page": 1,
  "limit": 20,
  "pages": 3
}
```

**Schedule Response:**
```
{
  "id": "schedule-xyz789",
  "cron": "0 0 * * * *",
  "enabled": true,
  "next_execution": "2025-01-15T11:00:00Z",
  "request": {
    "url": "https://api.example.com/health",
    "method": "GET"
  }
}
```