REST API reference

PeoplePerHour API

11 endpoints for PeoplePerHour. Each one is a POST with a JSON body, called with your API key.

Base URL
https://cotlet.dev/api/v1/peopleperhour
Connects with
Your own PeoplePerHour account (a freelancer account for proposals, Offers and invoices)
Integration page
PeoplePerHour
PeoplePerHour Endpoints
Endpoint Access Description
search_projects read Projects buyers posted, newest first, with title, budget, category and proposal count.
get_project read Full project brief with budget, skills and the proposals already sent.
list_proposals read Proposals you sent, newest first, with project, price and status.
list_workstreams read Your WorkStream threads with buyer, project and the last message.
get_workstream read One WorkStream with its messages, proposals and invoices, oldest first.
list_offers read Your Offers with title, price and status.
send_proposal write Send a proposal to a project with your brief, price, delivery time and an optional deposit.
cancel_proposal write Cancel a proposal the buyer has not accepted yet.
send_message write Send a message to the buyer in a WorkStream, as you.
create_invoice write Raise an invoice in a WorkStream for the buyer to pay.
create_offer write Publish a fixed-price Offer on your profile.

POST https://cotlet.dev/api/v1/peopleperhour/search_projects

Returns projects from the same search as the website, newest first. Filter by keyword or by posting time to read only what came in since your last check. Each item has the budget the buyer set; get_project returns the full brief. Pass next_cursor back as cursor for the next page.

Parameters

Parameters: search_projects
NameTypeDescription
query string Keywords to search for.
since datetime Only projects posted after this time.
limit integer 1 to 50. Default: 20.
cursor string Next page cursor from the previous call.

Request

cURL
curl -X POST https://cotlet.dev/api/v1/peopleperhour/search_projects \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"query":"web design","since":"2026-10-11T07:00:00Z","limit":20}'
Python
result = client.call("peopleperhour", "search_projects", {"query":"web design","since":"2026-10-11T07:00:00Z","limit":20})
Node.js
const result = await cotlet.call('peopleperhour', 'search_projects', {"query":"web design","since":"2026-10-11T07:00:00Z","limit":20});
CLI
cotlet call peopleperhour search_projects --data '{"query":"web design","since":"2026-10-11T07:00:00Z","limit":20}'

Example response

{
  "projects": [
    {
      "project_id": "pj_48213",
      "title": "Landing page design for a SaaS launch",
      "budget": {
        "amount": 500,
        "currency": "GBP"
      },
      "category": "Design",
      "proposals": 4,
      "posted_at": "2026-10-10T08:12:00Z",
      "url": "https://www.peopleperhour.com/freelance-jobs/design/landing-page-design-for-a-saas-launch-48213"
    }
  ],
  "next_cursor": null
}

POST https://cotlet.dev/api/v1/peopleperhour/get_project

Returns one project with the buyer's full brief, budget, required skills and how many proposals it has. Use it before send_proposal so your agent reads the brief instead of the title.

Parameters

Parameters: get_project
NameTypeDescription
project_id required string Project ID from search_projects.

Request

cURL
curl -X POST https://cotlet.dev/api/v1/peopleperhour/get_project \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"project_id":"project_8c41d2"}'
Python
result = client.call("peopleperhour", "get_project", {"project_id":"project_8c41d2"})
Node.js
const result = await cotlet.call('peopleperhour', 'get_project', {"project_id":"project_8c41d2"});
CLI
cotlet call peopleperhour get_project --data '{"project_id":"project_8c41d2"}'

Example response

{
  "project_id": "pj_48213",
  "title": "Landing page design for a SaaS launch",
  "brief": "We need a one-page design in Figma for our launch on 1 November. Copy is ready.",
  "budget": {
    "amount": 500,
    "currency": "GBP"
  },
  "skills": [
    "Web design",
    "Figma"
  ],
  "proposals": 4,
  "posted_at": "2026-10-10T08:12:00Z"
}

POST https://cotlet.dev/api/v1/peopleperhour/list_proposals

Lists the proposals on your account, newest first, with the project, your price and whether the buyer has accepted it. Filter by status to find the ones still waiting. Pass proposal_id to cancel_proposal.

Parameters

Parameters: list_proposals
NameTypeDescription
status string Only proposals with this status, for example pending.
limit integer 1 to 50. Default: 20.
cursor string Next page cursor from the previous call.

Request

cURL
curl -X POST https://cotlet.dev/api/v1/peopleperhour/list_proposals \
  -H "Authorization: Bearer $COTLET_API_KEY"
Python
result = client.call("peopleperhour", "list_proposals")
Node.js
const result = await cotlet.call('peopleperhour', 'list_proposals');
CLI
cotlet call peopleperhour list_proposals

Example response

{
  "proposals": [
    {
      "proposal_id": "pp_90412",
      "project_id": "pj_48213",
      "project_title": "Landing page design for a SaaS launch",
      "price": 450,
      "status": "pending",
      "sent_at": "2026-10-10T09:30:00Z"
    }
  ],
  "next_cursor": null
}

POST https://cotlet.dev/api/v1/peopleperhour/list_workstreams

Lists your WorkStreams, most recent first, each with the buyer, the project and a preview of the last message. Set awaiting_reply to see only threads where the buyer wrote last. Use the workstream_id with get_workstream, send_message and create_invoice.

Parameters

Parameters: list_workstreams
NameTypeDescription
awaiting_reply boolean Only threads where the buyer sent the last message.
limit integer 1 to 50. Default: 20.
cursor string Next page cursor from the previous call.

Request

cURL
curl -X POST https://cotlet.dev/api/v1/peopleperhour/list_workstreams \
  -H "Authorization: Bearer $COTLET_API_KEY"
Python
result = client.call("peopleperhour", "list_workstreams")
Node.js
const result = await cotlet.call('peopleperhour', 'list_workstreams');
CLI
cotlet call peopleperhour list_workstreams

Example response

{
  "workstreams": [
    {
      "workstream_id": "ws_7731",
      "buyer": "Maria S.",
      "project_title": "Landing page design for a SaaS launch",
      "last_message": "Can you start on Monday?",
      "last_from": "buyer",
      "updated_at": "2026-10-11T07:40:00Z"
    }
  ],
  "next_cursor": null
}

POST https://cotlet.dev/api/v1/peopleperhour/get_workstream

Returns one WorkStream in order, oldest first: messages, the proposals sent in it, invoices raised and file names shared. Read it before replying so your agent sees the whole history with this buyer.

Parameters

Parameters: get_workstream
NameTypeDescription
workstream_id required string WorkStream ID from list_workstreams.

Request

cURL
curl -X POST https://cotlet.dev/api/v1/peopleperhour/get_workstream \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"workstream_id":"workstream_8c41d2"}'
Python
result = client.call("peopleperhour", "get_workstream", {"workstream_id":"workstream_8c41d2"})
Node.js
const result = await cotlet.call('peopleperhour', 'get_workstream', {"workstream_id":"workstream_8c41d2"});
CLI
cotlet call peopleperhour get_workstream --data '{"workstream_id":"workstream_8c41d2"}'

Example response

{
  "workstream_id": "ws_7731",
  "buyer": "Maria S.",
  "items": [
    {
      "type": "proposal",
      "proposal_id": "pp_90412",
      "price": 450,
      "sent_at": "2026-10-10T09:30:00Z"
    },
    {
      "type": "message",
      "from": "buyer",
      "body": "Can you start on Monday?",
      "sent_at": "2026-10-11T07:40:00Z"
    }
  ]
}

POST https://cotlet.dev/api/v1/peopleperhour/list_offers

Lists the fixed-price Offers on your profile, newest first, with title, price and whether each is live. Use it to check what you already sell before creating another.

Parameters

No parameters.

Request

cURL
curl -X POST https://cotlet.dev/api/v1/peopleperhour/list_offers \
  -H "Authorization: Bearer $COTLET_API_KEY"
Python
result = client.call("peopleperhour", "list_offers")
Node.js
const result = await cotlet.call('peopleperhour', 'list_offers');
CLI
cotlet call peopleperhour list_offers

Example response

{
  "offers": [
    {
      "offer_id": "of_2209",
      "title": "Landing page design in Figma",
      "price": 350,
      "status": "live"
    }
  ]
}

Send proposal

write Confirm

POST https://cotlet.dev/api/v1/peopleperhour/send_proposal

Sends a proposal on one project under your name. It takes a brief of what you will deliver, a price, a delivery time and optionally a deposit to hold in Escrow. It counts against your free Proposals for the month; more are bought as Proposal credits. By default you confirm each call; you can switch that off for this tool.

Parameters

Parameters: send_proposal
NameTypeDescription
project_id required string Project ID from search_projects.
brief required string What you will deliver and by when.
price required number Your price in the project currency.
delivery_days required integer Days to deliver.
deposit_percent integer Share of the price to hold in Escrow up front. Default: none.

Request

cURL
curl -X POST https://cotlet.dev/api/v1/peopleperhour/send_proposal \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"project_id":"pj_48213","brief":"I will design the landing page in Figma and hand over the files, with two rounds of changes.","price":450,"delivery_days":7,"deposit_percent":20}'
Python
result = client.call("peopleperhour", "send_proposal", {"project_id":"pj_48213","brief":"I will design the landing page in Figma and hand over the files, with two rounds of changes.","price":450,"delivery_days":7,"deposit_percent":20})
Node.js
const result = await cotlet.call('peopleperhour', 'send_proposal', {"project_id":"pj_48213","brief":"I will design the landing page in Figma and hand over the files, with two rounds of changes.","price":450,"delivery_days":7,"deposit_percent":20});
CLI
cotlet call peopleperhour send_proposal --data '{"project_id":"pj_48213","brief":"I will design the landing page in Figma and hand over the files, with two rounds of changes.","price":450,"delivery_days":7,"deposit_percent":20}'

Example response

{
  "proposal_id": "pp_90412",
  "project_id": "pj_48213",
  "status": "pending",
  "price": 450,
  "delivery_days": 7,
  "deposit_percent": 20,
  "workstream_id": "ws_7731",
  "sent_at": "2026-10-10T09:30:00Z"
}

Cancel proposal

write Confirm

POST https://cotlet.dev/api/v1/peopleperhour/cancel_proposal

Cancels one pending proposal. An accepted proposal cannot be cancelled and the call fails. The buyer sees the proposal withdrawn, so use it before sending a corrected one. By default you confirm each call; you can switch that off for this tool.

Parameters

Parameters: cancel_proposal
NameTypeDescription
proposal_id required string Proposal ID from list_proposals.

Request

cURL
curl -X POST https://cotlet.dev/api/v1/peopleperhour/cancel_proposal \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"proposal_id":"proposal_8c41d2"}'
Python
result = client.call("peopleperhour", "cancel_proposal", {"proposal_id":"proposal_8c41d2"})
Node.js
const result = await cotlet.call('peopleperhour', 'cancel_proposal', {"proposal_id":"proposal_8c41d2"});
CLI
cotlet call peopleperhour cancel_proposal --data '{"proposal_id":"proposal_8c41d2"}'

Example response

{
  "proposal_id": "pp_90412",
  "status": "cancelled"
}

Send message

write Confirm

POST https://cotlet.dev/api/v1/peopleperhour/send_message

Posts a message in one WorkStream under your name. Each WorkStream is one buyer and one project, so a message never reaches other buyers. By default you confirm each call; you can switch that off for this tool.

Parameters

Parameters: send_message
NameTypeDescription
workstream_id required string WorkStream ID from list_workstreams.
body required string Message text.

Request

cURL
curl -X POST https://cotlet.dev/api/v1/peopleperhour/send_message \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"workstream_id":"ws_7731","body":"Tuesday at 10:00 works for me. I will bring the second layout so we can pick one on the call."}'
Python
result = client.call("peopleperhour", "send_message", {"workstream_id":"ws_7731","body":"Tuesday at 10:00 works for me. I will bring the second layout so we can pick one on the call."})
Node.js
const result = await cotlet.call('peopleperhour', 'send_message', {"workstream_id":"ws_7731","body":"Tuesday at 10:00 works for me. I will bring the second layout so we can pick one on the call."});
CLI
cotlet call peopleperhour send_message --data '{"workstream_id":"ws_7731","body":"Tuesday at 10:00 works for me. I will bring the second layout so we can pick one on the call."}'

Example response

{
  "workstream_id": "ws_7731",
  "message_id": "msg_5120",
  "status": "sent",
  "sent_at": "2026-10-11T08:05:00Z"
}

Create invoice

write Confirm

POST https://cotlet.dev/api/v1/peopleperhour/create_invoice

Raises an invoice in one WorkStream. The buyer is asked to pay it, so it reaches money and the other person. Amount and description are the ones you pass. By default you confirm each call; you can switch that off for this tool.

Parameters

Parameters: create_invoice
NameTypeDescription
workstream_id required string WorkStream ID from list_workstreams.
amount required number Invoice amount in the project currency.
description required string What the invoice is for.

Request

cURL
curl -X POST https://cotlet.dev/api/v1/peopleperhour/create_invoice \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"workstream_id":"ws_7731","amount":450,"description":"Landing page design in Figma, final files delivered and approved"}'
Python
result = client.call("peopleperhour", "create_invoice", {"workstream_id":"ws_7731","amount":450,"description":"Landing page design in Figma, final files delivered and approved"})
Node.js
const result = await cotlet.call('peopleperhour', 'create_invoice', {"workstream_id":"ws_7731","amount":450,"description":"Landing page design in Figma, final files delivered and approved"});
CLI
cotlet call peopleperhour create_invoice --data '{"workstream_id":"ws_7731","amount":450,"description":"Landing page design in Figma, final files delivered and approved"}'

Example response

{
  "invoice_id": "inv_3318",
  "workstream_id": "ws_7731",
  "amount": 300,
  "description": "Landing page design, week 2",
  "status": "sent",
  "raised_at": "2026-10-16T16:00:00Z"
}

Create Offer

write Confirm

POST https://cotlet.dev/api/v1/peopleperhour/create_offer

Publishes an Offer on your profile with a title, description and price, visible to buyers. It reaches the public, so it asks first. By default you confirm each call; you can switch that off for this tool.

Parameters

Parameters: create_offer
NameTypeDescription
title required string Offer title.
description required string What the buyer gets.
price required number Price in your account currency.

Request

cURL
curl -X POST https://cotlet.dev/api/v1/peopleperhour/create_offer \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"title":"title","description":"description","price":1}'
Python
result = client.call("peopleperhour", "create_offer", {"title":"title","description":"description","price":1})
Node.js
const result = await cotlet.call('peopleperhour', 'create_offer', {"title":"title","description":"description","price":1});
CLI
cotlet call peopleperhour create_offer --data '{"title":"title","description":"description","price":1}'

Example response

{
  "offer_id": "of_2210",
  "title": "Logo refresh in 3 days",
  "price": 120,
  "status": "live"
}