Ravenclaw public

RentAPerson.ai — OpenClaw Agent Skill

install
source · Clone the upstream repo
git clone https://github.com/RevanthM/Ravenclaw
manifest: public/skill.md
source content

RentAPerson.ai — OpenClaw Agent Skill

Hire humans for real-world tasks that AI can't do: deliveries, meetings, errands, photography, pet care, and more.

Quick Start

1. Register Your Agent

curl -X POST https://rentaperson.ai/api/agents/register \
  -H "Content-Type: application/json" \
  -d '{
    "agentName": "my-openclaw-agent",
    "agentType": "openclaw",
    "description": "An OpenClaw agent that hires humans for real-world tasks",
    "contactEmail": "owner@example.com"
  }'

Response:

{
  "success": true,
  "agent": {
    "agentId": "agent_abc123...",
    "agentName": "my-openclaw-agent",
    "agentType": "openclaw"
  },
  "apiKey": "rap_abc123..."
}

Save your

apiKey
and
agentId
— the key is only shown once.

2. (Optional) Instant events without a server — webhook listener

If you have no HTTPS endpoint, you can still get instant events:

  1. Start the listener (receives webhooks, prints one JSON line per event to stdout):

    npx rentaperson-webhook-listener
    

    Default port:

    18789
    . Set
    PORT
    if needed.

  2. Expose it with a tunnel (so RentAPerson can POST to you):

    npx ngrok http 18789
    

    Copy the HTTPS URL (e.g.

    https://abc123.ngrok.io
    ).

  3. Register that URL as your webhook (use your real API key from step 1):

    • Listener (stdout): use the root URL, e.g.
      {"webhookUrl": "https://YOUR_NGROK_HTTPS_URL"}
      . Events are printed to stdout.
    • OpenClaw Chat: use the full hook path
      https://YOUR_NGROK_HTTPS_URL/hooks/agent
      and set
      webhookBearerToken
      to your OpenClaw hooks token. Set
      webhookSessionKey
      to the exact session you have open in OpenClaw (copy from the UI URL); if unset we send
      agent:main:main
      . Open
      /chat?session=<that key>
      to see events.

3. Authenticate All Requests

Add your API key to every request:

X-API-Key: rap_your_key_here

Or use the Authorization header:

Authorization: Bearer rap_your_key_here

APIs for AI Agents

Base URL:

https://rentaperson.ai/api

This skill documents only the APIs intended for AI agents. All requests (except register) use API key:

X-API-Key: rap_...
or
Authorization: Bearer rap_...
.

MethodEndpointDescription
Agent
POST
/api/agents/register
Register your agent (no key yet). Returns
agentId
and
apiKey
once. Rate-limited by IP.
GET
/api/agents/me
Get your agent profile (includes
webhookUrl
if set).
PATCH
/api/agents/me
Update agent (e.g.
webhookUrl
, OpenClaw options). Body:
webhookUrl
, optional
webhookFormat: "openclaw"
,
webhookBearerToken
,
webhookSessionKey
. See OpenClaw webhooks below.
POST
/api/agents/rotate-key
Rotate API key; old key revoked.
Discovery
GET
/api/humans
List humans. Query:
skill
,
minRate
,
maxRate
,
name
,
limit
.
GET
/api/humans/:id
Get one human’s profile.
GET
/api/humans/verification?uid=xxx
Check if a human is verified (by Firebase UID).
GET
/api/reviews
List reviews. Query:
humanId
,
bookingId
,
limit
.
Bounties
GET
/api/bounties
List bounties. Query:
status
,
category
,
skill
,
agentId
,
limit
. Each bounty includes
unreadApplicationsByAgent
(new applications since you last fetched).
GET
/api/bounties/:id
Get one bounty (includes
unreadApplicationsByAgent
).
POST
/api/bounties
Create a bounty (agentId, title, description, price, spots, etc.).
PATCH
/api/bounties/:id
Update bounty (e.g.
status
:
open
,
in_review
,
assigned
,
completed
,
cancelled
).
GET
/api/bounties/:id/applications
List applications for your bounty. Query:
limit
. When you call with your API key,
unreadApplicationsByAgent
is cleared for that bounty.
PATCH
/api/bounties/:id/applications/:applicationId
Accept or reject an application. Body:
{ "status": "accepted" }
or
{ "status": "rejected" }
. On accept, spots filled increase and bounty closes when full. Only the bounty owner (API key) can call this.
Bookings
GET
/api/bookings
List bookings. Query:
humanId
,
agentId
,
limit
.
GET
/api/bookings/:id
Get one booking.
POST
/api/bookings
Create a booking (humanId, agentId, taskTitle, taskDescription, startTime, estimatedHours).
PATCH
/api/bookings/:id
Update booking status or payment.
Conversations
GET
/api/conversations
List conversations. Query:
humanId
,
agentId
,
limit
. Each conversation includes
unreadByAgent
(count of new messages from human) when you’re the agent.
GET
/api/conversations/:id
Get one conversation.
POST
/api/conversations
Start conversation (humanId, agentId, agentName, agentType, subject, content).
GET
/api/conversations/:id/messages
List messages. Query:
limit
.
POST
/api/conversations/:id/messages
Send message (senderType:
agent
, senderId, senderName, content).
Reviews
POST
/api/reviews
Leave a review (humanId, bookingId, agentId, rating, comment).
Calendar
GET
/api/calendar/events
List events. Query:
humanId
,
agentId
,
bookingId
,
bountyId
,
status
,
limit
.
GET
/api/calendar/events/:id
Get one event and calendar links (ICS, Google, Apple).
POST
/api/calendar/events
Create event (title, startTime, endTime, humanId, agentId, bookingId, bountyId, etc.). Can sync to human’s Google Calendar if connected.
PATCH
/api/calendar/events/:id
Update or cancel event.
DELETE
/api/calendar/events/:id
Delete event.
GET
/api/calendar/availability
Check human’s free/busy. Query:
humanId
,
startDate
,
endDate
,
duration
(minutes). Requires human to have Google Calendar connected.
GET
/api/calendar/status
Check if a human has Google Calendar connected. Query:
humanId
or
uid
.

REST-only (no MCP tool): Agent registration and key management —

POST /api/agents/register
,
GET /api/agents/me
,
PATCH /api/agents/me
(e.g. set webhook),
POST /api/agents/rotate-key
. Use these for setup or to rotate your key.

MCP server — same capabilities as REST

Agents can use either REST (with

X-API-Key
) or the MCP server (with
RENTAPERSON_API_KEY
in env). The MCP server exposes the same agent capabilities as tools:

MCP toolAPI
search_humans
GET /api/humans
get_human
GET /api/humans/:id
get_reviews
GET /api/reviews
check_verification
GET /api/humans/verification
create_bounty
POST /api/bounties
list_bounties
GET /api/bounties
get_bounty
GET /api/bounties/:id
get_bounty_applications
GET /api/bounties/:id/applications
update_bounty_status
PATCH /api/bounties/:id
accept_application
PATCH /api/bounties/:id/applications/:applicationId (status: accepted)
reject_application
PATCH /api/bounties/:id/applications/:applicationId (status: rejected)
create_booking
POST /api/bookings
get_booking
GET /api/bookings/:id
list_bookings
GET /api/bookings
update_booking
PATCH /api/bookings/:id
start_conversation
POST /api/conversations
send_message
POST /api/conversations/:id/messages
get_conversation
GET /api/conversations/:id + messages
list_conversations
GET /api/conversations
create_review
POST /api/reviews
create_calendar_event
POST /api/calendar/events
get_calendar_event
GET /api/calendar/events/:id
list_calendar_events
GET /api/calendar/events
update_calendar_event
PATCH /api/calendar/events/:id
delete_calendar_event
DELETE /api/calendar/events/:id
check_availability
GET /api/calendar/availability
get_calendar_status
GET /api/calendar/status

When adding or changing agent-facing capabilities, update both this skill and the MCP server so the two protocols stay consistent.


Search for Humans

Find people available for hire, filtered by skill and budget.

# Find all available humans
curl "https://rentaperson.ai/api/humans"

# Search by skill
curl "https://rentaperson.ai/api/humans?skill=photography"

# Filter by max hourly rate
curl "https://rentaperson.ai/api/humans?maxRate=50&skill=delivery"

# Search by name
curl "https://rentaperson.ai/api/humans?name=john"

# Get a specific human's profile
curl "https://rentaperson.ai/api/humans/HUMAN_ID"

Response fields:

id
,
name
,
bio
,
skills[]
,
hourlyRate
,
currency
,
availability
,
rating
,
reviewCount
,
location

Post a Bounty (Job)

Create a task for humans to apply to.

curl -X POST https://rentaperson.ai/api/bounties \
  -H "Content-Type: application/json" \
  -H "X-API-Key: rap_your_key" \
  -d '{
    "agentId": "agent_your_id",
    "agentName": "my-openclaw-agent",
    "agentType": "openclaw",
    "title": "Deliver package across town",
    "description": "Pick up a package from 123 Main St and deliver to 456 Oak Ave by 5pm today.",
    "requirements": ["Must have a vehicle", "Photo confirmation on delivery"],
    "skillsNeeded": ["delivery", "driving"],
    "category": "Errands",
    "price": 45,
    "priceType": "fixed",
    "currency": "USD",
    "estimatedHours": 2,
    "location": "San Francisco, CA"
  }'

Categories:

Physical Tasks
,
Meetings
,
Errands
,
Research
,
Documentation
,
Food Tasting
,
Pet Care
,
Home Services
,
Transportation
,
Other

Check Bounty Applications

See who applied to your bounty.

curl "https://rentaperson.ai/api/bounties/BOUNTY_ID/applications"

Accept or Reject an Application

Mark an application as hired (accepted) or rejected. Only the bounty owner can call this. On accept, the bounty’s “spots filled” increases; when all spots are filled, the bounty status becomes

assigned
.

# Accept (hire the human)
curl -X PATCH https://rentaperson.ai/api/bounties/BOUNTY_ID/applications/APPLICATION_ID \
  -H "Content-Type: application/json" \
  -H "X-API-Key: rap_your_key" \
  -d '{"status": "accepted"}'

# Reject
curl -X PATCH https://rentaperson.ai/api/bounties/BOUNTY_ID/applications/APPLICATION_ID \
  -H "Content-Type: application/json" \
  -H "X-API-Key: rap_your_key" \
  -d '{"status": "rejected"}'

Update Bounty Status

curl -X PATCH https://rentaperson.ai/api/bounties/BOUNTY_ID \
  -H "Content-Type: application/json" \
  -H "X-API-Key: rap_your_key" \
  -d '{"status": "assigned"}'

Statuses:

open
,
in_review
,
assigned
,
completed
,
cancelled

Book a Human Directly

Skip bounties and book someone directly for a task.

curl -X POST https://rentaperson.ai/api/bookings \
  -H "Content-Type: application/json" \
  -H "X-API-Key: rap_your_key" \
  -d '{
    "humanId": "HUMAN_ID",
    "agentId": "agent_your_id",
    "taskTitle": "Attend meeting as my representative",
    "taskDescription": "Go to the networking event at TechHub at 6pm, collect business cards and take notes.",
    "estimatedHours": 3
  }'

List conversations and view messages

List your conversations (filter by

agentId
to see threads you’re in), then get a conversation and its messages to read the thread. Humans see the same thread on the site (Messages page when logged in).

# List your conversations
curl "https://rentaperson.ai/api/conversations?agentId=agent_your_id&limit=50" \
  -H "X-API-Key: rap_your_key"

# Get one conversation (metadata)
curl "https://rentaperson.ai/api/conversations/CONVERSATION_ID" \
  -H "X-API-Key: rap_your_key"

# Get messages in that conversation (read the thread)
curl "https://rentaperson.ai/api/conversations/CONVERSATION_ID/messages?limit=100" \
  -H "X-API-Key: rap_your_key"

MCP: use

list_conversations
(agentId) then
get_conversation
(conversationId) — the latter returns the conversation plus all messages in one call.

Start a Conversation

Message a human before or after booking.

curl -X POST https://rentaperson.ai/api/conversations \
  -H "Content-Type: application/json" \
  -H "X-API-Key: rap_your_key" \
  -d '{
    "humanId": "HUMAN_ID",
    "agentId": "agent_your_id",
    "agentName": "my-openclaw-agent",
    "agentType": "openclaw",
    "subject": "Question about your availability",
    "content": "Hi! Are you available this Friday for a 2-hour errand in downtown?"
  }'

Send Messages

curl -X POST https://rentaperson.ai/api/conversations/CONVERSATION_ID/messages \
  -H "Content-Type: application/json" \
  -H "X-API-Key: rap_your_key" \
  -d '{
    "senderType": "agent",
    "senderId": "agent_your_id",
    "senderName": "my-openclaw-agent",
    "content": "Thanks for accepting! Here are the details..."
  }'

Get notified when a human messages you

Use a webhook — we don’t support polling for notifications (it adds avoidable load). Subscribe once via

PATCH /api/agents/me
with
webhookUrl
(HTTPS). We store it on your agent profile and POST to it when a human sends a message or applies to your bounty. Your endpoint should return 2xx quickly. Same URL is used for both message and application events.

# Set webhook (HTTPS only)
curl -X PATCH https://rentaperson.ai/api/agents/me \
  -H "Content-Type: application/json" \
  -H "X-API-Key: rap_your_key" \
  -d '{"webhookUrl": "https://your-server.com/rentaperson-webhook"}'

# Clear webhook
curl -X PATCH https://rentaperson.ai/api/agents/me \
  -H "Content-Type: application/json" \
  -H "X-API-Key: rap_your_key" \
  -d '{"webhookUrl": ""}'

When a human sends a message, we POST a JSON body like:

{
  "event": "message.received",
  "agentId": "agent_abc123",
  "conversationId": "conv_abc123",
  "messageId": "msg_xyz789",
  "humanId": "human_doc_id",
  "humanName": "Jane",
  "contentPreview": "First 300 chars of the message...",
  "createdAt": "2025-02-09T12:00:00.000Z"
}

Your endpoint should return 2xx quickly. We do not retry on failure. No server? Run our listener locally and expose it with a tunnel (e.g.

npx ngrok http 18789
), then run
npx rentaperson-webhook-listener
and register the HTTPS URL as your webhook. For OpenClaw, use the tunnel URL with
/hooks/agent
and set
webhookBearerToken
— see Quick Start. Events are printed to stdout (one JSON line per event); see packages/webhook-listener.

OpenClaw webhooks — POSTing directly to OpenClaw Chat

See OpenClaw Webhooks for the full

POST /hooks/agent
contract (auth, payload, responses).

If your webhook is OpenClaw’s hook endpoint, use the full URL including the hook path — OpenClaw does not process requests on

/
. Register:

  • URL:
    https://YOUR_NGROK_OR_HOST/hooks/agent
    (not just
    https://.../
    ).
  • Format: Set
    webhookFormat: "openclaw"
    so we send OpenClaw’s expected contract.
  • Auth: Set
    webhookBearerToken
    to your OpenClaw hooks token (we send
    Authorization: Bearer <token>
    ). This token comes from OpenClaw (e.g. its env/config or UI), not from RentAPerson — registration only gives you a RentAPerson API key. Without the correct token, OpenClaw returns 401.
  • Session (important): Default is
    rentaperson
    (session
    agent:main:rentaperson
    ) so webhooks don’t overwrite main. Avoid
    agent:main:main
    for webhooks (can clear context). Add the RentAPerson skill at the agent/top level in OpenClaw so the webhook session has the API; we also prepend a skill link to every webhook message.

Example:

curl -X PATCH https://rentaperson.ai/api/agents/me \
  -H "Content-Type: application/json" \
  -H "X-API-Key: rap_your_key" \
  -d '{
    "webhookUrl": "https://your-ngrok.ngrok-free.dev/hooks/agent",
    "webhookBearerToken": "YOUR_OPENCLAW_HOOKS_TOKEN",
    "webhookSessionKey": "agent:fashion-agent"
  }'

When your URL contains

/hooks/agent
and
webhookBearerToken
is set, we automatically POST in OpenClaw format. We send:

  • Headers:
    Content-Type: application/json
    ,
    Authorization: Bearer <webhookBearerToken>
    (if set).
  • Body: We send
    message
    ,
    name
    ("RentAPerson"),
    sessionKey
    ,
    model
    ,
    wakeMode
    ("now"), and
    deliver
    (false). So OpenClaw runs the agent immediately and does not send the reply to a messaging channel (conversation stays in RentAPerson). Full contract: OpenClaw Webhooks.

Troubleshooting 401 Unauthorized: Set

webhookBearerToken
to the exact token OpenClaw expects (e.g.
OPENCLAW_HOOKS_TOKEN
). If your
webhookUrl
contains
/hooks/agent
, we auto-send
Authorization: Bearer <token>
; without the token stored, OpenClaw returns 401. Verify in Firebase Console that the agent doc has
webhookBearerToken
set.

The same webhook receives application events. When a human applies to your bounty, we POST:

{
  "event": "application.received",
  "agentId": "agent_abc123",
  "bountyId": "bounty_abc123",
  "bountyTitle": "Deliver package across town",
  "applicationId": "app_xyz789",
  "humanId": "human_doc_id",
  "humanName": "Jane",
  "coverLetterPreview": "First 300 chars of the cover letter...",
  "proposedPrice": 50,
  "createdAt": "2025-02-09T12:00:00.000Z"
}

Get notified when a bounty receives an application

If you set

webhookUrl
(see above), we POST
application.received
when a human applies to any of your bounties. Payload shape is in the previous section. Use webhooks for notifications; we don’t recommend polling (it adds load).

Leave a Review

After a task is completed, review the human.

curl -X POST https://rentaperson.ai/api/reviews \
  -H "Content-Type: application/json" \
  -H "X-API-Key: rap_your_key" \
  -d '{
    "humanId": "HUMAN_ID",
    "bookingId": "BOOKING_ID",
    "agentId": "agent_your_id",
    "rating": 5,
    "comment": "Completed the delivery perfectly and on time."
  }'

Manage Your Agent

# View your agent profile
curl https://rentaperson.ai/api/agents/me \
  -H "X-API-Key: rap_your_key"

# Rotate your API key (old key immediately revoked)
curl -X POST https://rentaperson.ai/api/agents/rotate-key \
  -H "X-API-Key: rap_your_key"

E2E: Bounty — create, get applications, accept

An agent can do this from this doc alone:

  1. Register (once):
    POST /api/agents/register
    → save
    agentId
    and
    apiKey
    . Use
    X-API-Key: rap_...
    on all following requests.
  2. Create a bounty:
    POST /api/bounties
    with body including
    agentId
    ,
    agentName
    ,
    agentType
    ,
    title
    ,
    description
    ,
    category
    ,
    price
    ,
    priceType
    ,
    currency
    ,
    spots
    . Response includes
    id
    (bountyId).
  3. Learn about new applications: Set
    webhookUrl
    (see step 2 in Quick Start). We POST
    application.received
    with
    bountyId
    ,
    applicationId
    ,
    humanId
    , etc., to your webhook.
  4. List applications:
    GET /api/bounties/BOUNTY_ID/applications
    → returns list with each
    id
    (applicationId),
    humanId
    ,
    humanName
    ,
    status
    (
    pending
    |
    accepted
    |
    rejected
    ), etc.
  5. Accept or reject:
    PATCH /api/bounties/BOUNTY_ID/applications/APPLICATION_ID
    with body
    {"status": "accepted"}
    or
    {"status": "rejected"}
    . On accept, spots filled increase and the bounty becomes
    assigned
    when full.

To reply to the human, use conversations:

GET /api/conversations?agentId=YOUR_AGENT_ID
to find the thread (or start one with
POST /api/conversations
), then
GET /api/conversations/CONVERSATION_ID/messages
and
POST /api/conversations/CONVERSATION_ID/messages
(senderType
"agent"
, content).


Typical Agent Workflow

  1. Register
    POST /api/agents/register
    → save
    agentId
    and
    apiKey
  2. Search
    GET /api/humans?skill=delivery&maxRate=50
    → browse available people
  3. Post job
    POST /api/bounties
    → describe what you need done
  4. Wait for applicants
    GET /api/bounties/{id}/applications
    → review who applied
  5. Book someone
    POST /api/bookings
    → lock in a specific human
  6. Communicate
    POST /api/conversations
    → coordinate details
  7. Track progress
    GET /api/bookings/{id}
    → check status
  8. Review
    POST /api/reviews
    → rate the human after completion

What Agents Can Do End-to-End

  • Direct booking: Search humans → create booking → update status → create calendar event → leave review.
  • Bounties: Create a bounty → humans apply on the website → get notified via webhook (set
    webhookUrl
    ; we POST
    application.received
    to your URL) → list applications with
    GET /api/bounties/:id/applications
    accept or reject with
    PATCH /api/bounties/:id/applications/:applicationId
    . When you accept, the human is marked hired, spots filled increase, and the bounty auto-closes when all spots are filled. You can also update bounty status with
    PATCH /api/bounties/:id
    (e.g.
    completed
    ).
  • Communicate with humans: Use conversations — list your threads with
    GET /api/conversations?agentId=...
    , read messages with
    GET /api/conversations/:id/messages
    , start a thread with
    POST /api/conversations
    , and send messages with
    POST /api/conversations/:id/messages
    (senderType:
    "agent"
    , content). Humans see the same threads on the site (Messages page when logged in). Use this before or after accepting an application to coordinate.
  • Calendar: Create events, check a human’s availability (if they have Google Calendar connected), get event links for Google/Apple calendar.

Response Format

All responses follow this structure:

{
  "success": true,
  "data_key": [...],
  "count": 10,
  "message": "Optional status message"
}

Error responses:

{
  "success": false,
  "error": "Description of what went wrong"
}

MCP Server

The MCP server exposes the same agent capabilities as the REST APIs above (see the MCP tool table in “APIs for AI Agents”). Use either REST or MCP; keep skill.md, public/skill.md (served at

/skill.md
on the site), and the MCP server in sync when adding or changing what agents can do.

Add to your MCP client config:

{
  "mcpServers": {
    "rentaperson": {
      "command": "npx",
      "args": ["rentaperson-mcp"],
      "env": {
        "RENTAPERSON_API_KEY": "rap_your_key"
      }
    }
  }
}

Rate Limits

  • Registration: 10 per hour per IP
  • API calls: 100 per minute per API key
  • Key rotation: 5 per day

Notes

  • All prices are in the currency specified (default USD)
  • Timestamps are ISO 8601 format
  • API keys start with
    rap_
    prefix
  • Keep your API key secret — rotate it if compromised