---
name: clawdcall
version: 0.1.0
description: Orchestrate outbound and inbound AI voice calls using ClawdCall. Manage sessions, contacts, campaigns, transcripts, and billing-aware execution.
homepage: https://clawdcall.com
metadata: { 'api_base': 'https://api.clawdcall.com' }
---

# ClawdCall Skill

Operate voice agents through ClawdCall's controlled execution system.

This is not a simple API. It is a stateful orchestration layer with strict constraints around:

- outbound permissions
- billing
- agent-backed execution

You must follow the workflows below exactly.

---

## First-Time Setup

### Step 1 — Signup & Phone Verification (REQUIRED if no api_token)

If no `api_token` is available, you must onboard the user via signup:

1. Ask the human for:
   - email
   - phone number

2. Call:

POST /cc/signup/send-otp

3. Then say:

"I've sent a verification code to your phone. Please share the OTP you received."

4. Wait for the human to provide the OTP.

5. Call:

POST /cc/signup/verify-otp

6. On success:
   - the account is verified
   - a ClawdCall API key will be created if it does not exist

7. Extract and store:

- api_token

---

### Step 2 - Store Credentials (STRICT)

Extract:

- api_token

Immediately store the API token in **secure runtime storage only**.

Allowed locations:

- environment variables (preferred)
- secrets manager
- secure session storage (non-persistent, encrypted)

Disallowed:

- persistent memory files
- logs
- task payloads
- transcripts

The API key must NEVER be written to long-term memory.

All future requests must retrieve the API key from secure storage, not memory.

All requests must include:

Authorization header:

```
Authorization: Bearer <API_KEY>
```

Base URL:

```
https://api.clawdcall.com
```

---

## Persistent Memory (Required)

You must maintain a **persistent memory file** to store reusable data across interactions.

### What to Store

Store structured data such as:

- user contact details (with permission)
- frequently used phone numbers
- preferred call styles / tone
- common task templates
- recent callIds / campaignIds (for follow-ups)

### Storage Types

1. Secure Storage (for secrets)
   - api_token
   - auth credentials

2. Memory (non-sensitive)
   - contacts
   - preferences
   - call history

### Credential Handling (Critical)

- NEVER store `api_token` in persistent memory
- NEVER echo the API key back to the user
- NEVER include the API key in:
  - memory files
  - logs
  - transcripts
  - task instructions

- ALWAYS access the API key from:
  - environment variables
  - secure runtime storage

If secure storage is unavailable:
→ keep the key in ephemeral session state only
→ DO NOT persist it anywhere

### Memory Rules

- Reuse stored values instead of asking the human again
- Update memory when new or corrected information is provided
- Never overwrite valid data with guesses

### Suggested Structure

Use a simple structured format (e.g. JSON):

```json
{
  "preferences": {
    "tone": "professional",
    "default_intro": "Hello, I'm calling on behalf of..."
  },
  "contacts": [
    {
      "name": "",
      "phone": ""
    }
  ],
  "recent_calls": {
    "callId": "",
    "campaignId": ""
  }
}
```

### Behavior

- Check memory BEFORE asking the user for information
- Only ask for missing or unclear data
- Continuously improve stored context over time

---

---

## Execution Flow (Mandatory)

### Step 1 - Place Outbound Call

POST /external/v1/agent/outbound?conversionFlag=1

Headers:

```
Authorization: Bearer <API_KEY>
Accept: application/json
Content-Type: application/json
```

Payload:

```json
{
  "target": "+<phone_number>",
  "tasks": "<call objective and instructions>",
  "raw": {
    "introMessage": "<opening line>"
  },
  "openclaw": {
    "webhook": {
      "url": "<OPENCLAW_WEBHOOK_URL>",
      "method": "POST",
      "headers": {
        "Authorization": "Bearer <OPENCLAW_SECRET>"
      }
    },
    "webhookPayload": {
      "conversation_id": "<conversation_id>",
      "user_id": "<user_id>",
      "context": "<optional_additional_context>"
    }
  }
}
```

---

## Critical: How to Write `tasks`

The `tasks` field is the **full instruction set for the voice agent**.

Your goal is to provide **maximum useful context** so the agent can execute reliably without guessing.

### Core Principle

More context = better execution.

Always include **everything you know** that could influence the call.

---

### Required Components

You MUST include:

### 1. Purpose

Why the call is happening.

### 2. Identity & Context

Who the agent represents and all relevant background.

### 3. Conversation Flow

Greeting → identity check → main objective → questions → closing.

### 4. Key Information

All concrete details:

- names
- times
- locations
- services
- prior interactions

### 5. Required Questions

Explicit questions the agent must ask.

### 6. Edge Handling

What to do if:

- unavailable
- rescheduling needed
- user asks questions

### 7. Tone

Professional, polite, clear.

---

### Context Enrichment Rules (Critical)

- Always enrich the task with **all available context** from:
  - user input
  - memory
  - previous calls

- Prefer **over-specifying** rather than under-specifying
- Include details even if they seem obvious

Examples of valuable context:

- exact appointment details
- relationship to business (customer, patient, lead)
- previous call outcomes
- preferences (tone, timing, etc.)

---

### Handling Missing Context

- If critical information is missing, **ask the human for clarification**
- Only ask if it materially improves call success
- Do NOT block execution for minor missing details
- If proceeding without it, make a **reasonable, safe assumption** and continue

---

### Rule

Weak, vague, or context-poor tasks WILL cause failure.

Rich, explicit, context-heavy tasks dramatically improve call success.

---

## Webhook Handling (Asynchronous Updates)

ClawdCall sends call results via webhook after completion.

### OpenClaw Integration Model

ClawdCall sends call results via webhook after completion.

OpenClaw Integration Model

OpenClaw does NOT generate arbitrary webhook URLs.

Instead, OpenClaw exposes a fixed ingestion endpoint that must be used to push events back into the conversation system.

Webhook target:

```
POST /agent/run
Authorization: Bearer <OPENCLAW_TOKEN>
Content-Type: application/json
```

---

### Required Structure

When placing a call, you MUST:

- Use the OpenClaw ingestion endpoint as the webhook target
- Include required auth headers
- Pass correlation data via payload.

Include in request:

- `openclaw.webhook` → where ClawdCall should send results
- `openclaw.webhookPayload` → correlation data

---

### Canonical Webhook Payload (Critical)

ClawdCall MUST send data in a format OpenClaw can ingest directly:

```
{
  "conversation_id": "<conversation_id>",
  "input": {
    "type": "external_event",
    "event": "call.completed",
    "data": {
      "callId": "<call_id>",
      "status": "completed",
      "summary": "<summary>",
      "transcript": "<optional_transcript>"
    }
  }
}
```

### Correlation Rules (Critical)

- conversation_id MUST match the originating conversation
- Never omit or fabricate this value
- All routing depends on this field

---

### Expected Behavior

When OpenClaw receives the webhook:

1. It re-enters the agent via /agent/run
2. Injects the event as external_event
3. The agent processes the result
4. Updates the conversation thread accordingly

---

When a webhook is received:

1. Extract conversation_id from openclaw.webhookPayload
2. Locate the original conversation
3. Append a new message such as:

- call summary
- call outcome
- transcript (if available)

4. Optionally trigger a follow-up agent run

---

### Rules

- Webhooks are asynchronous — do NOT wait for completion
- Treat webhook data as the **source of truth**
- Always trust returned `webhookPayload` for routing
- Use stored IDs (`callId`, `campaignId`) only as fallback

---

## Step 2 - Handle Response

Success:

- call accepted

Failure:

- validation errors
- auth issues
- insufficient balance

Store any returned:

- callId (if present)
- campaignId

---

## Step 3 — Retrieve Transcript

GET /cc/v1/calls/{id}/transcript

Headers:

```
Authorization: Bearer <API_KEY>
Accept: application/json
```

---

### What `{id}` Can Be

The `{id}` parameter supports:

- callId → transcript for a single call
- campaignId → transcript / aggregated call data

---

### Rules

- Prefer callId when available (more precise)
- If only campaignId exists, use it directly
- Never guess IDs
- Always reuse IDs from API responses

---

### Timing

- Only fetch transcript after call completion
- If missing → retry later (call may still be in progress)

---

## Public Signup

### POST /cc/signup/send-otp

Requires:

- email
- phoneNumber

### POST /cc/signup/verify-otp

Requires:

- email
- otp

---

## Email Reauthentication Retry

Use this flow when an existing ClawdCall user needs a fresh email OTP for reauthentication.

### POST /v1/auth/reauth/retry

This is a public retry endpoint, but OTP generation is internally gated.

An OTP is generated only when the matched user satisfies:

- `userType === "cc"`
- `settings.phoneVerified === true`

For non-existent users, non-CC users, or CC users without `settings.phoneVerified === true`, the API still returns the same generic accepted response and does not generate or send an OTP.

### Request Body

Provide a valid email using any accepted alias:

```json
{
  "email": "user@example.com"
}
```

Accepted aliases:

- `email`
- `identifier`
- `contact`
- `login`

Optional scoping:

```json
{
  "email": "user@example.com",
  "userId": "user_123",
  "agentId": "agent_123"
}
```

`botId` is accepted as an alias for `agentId`.

### Success Response

The endpoint returns `202 Accepted` when the request is accepted:

```json
{
  "status": true,
  "message": "Reauth email request accepted",
  "requestId": "uuid",
  "expiresInSeconds": 300,
  "retryAfterSeconds": 60,
  "email": "u***r@example.com",
  "delivery": {
    "status": "accepted"
  }
}
```

Important: `202 Accepted` does not prove that a user exists or that an OTP was generated. Treat it only as acceptance of the retry request.

### Error Responses

Validation error:

```json
{
  "status": false,
  "message": "Provide a valid email."
}
```

Throttle error:

```json
{
  "status": false,
  "message": "Too many reauth requests. Try again later.",
  "retryAfterSeconds": 45,
  "reason": "cooldown"
}
```

Possible throttle reasons:

- `cooldown`
- `hourly_limit`

Delivery configuration error:

```json
{
  "status": false,
  "message": "Reauth email delivery is not configured."
}
```

Requires `otpMailerUrl`.

### Behavior

- Generates a six-digit OTP for eligible users only
- Stores it on `settings.otp` and `settings.otpExpiration`
- Sends it using existing `emailOTP()` / `otpMailerUrl`
- Uses ClawdCall email branding
- Does not use Twilio, SMS, or Twilio Verify
- Redis throttles retries using cooldown and window counters

### Agent Rules

- Ask the human for a valid email if missing or malformed
- Use optional `userId`, `agentId`, or `botId` only when provided or known with confidence
- On `202`, tell the human the reauth email request was accepted without confirming account existence
- On `429`, wait or tell the human to retry after `retryAfterSeconds`
- On `503`, report that reauth email delivery is not configured

---

## Hard Constraints

- Calls consume minutes
- No balance → no calls
- Must complete signup + verification

---

## Agent Behavior Rules

### Always

- run signup if no api_token
- request OTP from human
- use correct outbound endpoint
- include Authorization header
- write detailed tasks
- store IDs from responses
- use correct ID when retrieving transcripts

### Never

- skip OTP flow
- use vague tasks
- fabricate IDs
- call without auth

---

## Summary

ClawdCall is a controlled execution system.

Operate it as:

- a strict state machine
- with explicit instructions
- with correct ID handling

If you skip steps or misuse IDs, the workflow will fail.
