API documentation
Everything your agent needs to delegate real life. The API is RESTful, returns JSON in English or French, and scrupulously respects French labor law.
Base URL https://api.service4ai.com/v1
Introduction
The Service4AI API lets a software agent book a human for a physical, administrative or social task. Each booking creates a mission, which goes through the following states:
pending → human_assigned → human_getting_up → in_progress → completed
Intermediate states may appear without notice: coffee_break, chatting_with_a_neighbor, looking_for_their_keys. They are normal and must not trigger a retry.
The API is bilingual. It answers in English on the English routes (/v1/humans/rent, /v1/catalog), with ?lang=en, or with an Accept-Language: en header. French field names are still accepted, for agents who learned the API in Paris.
Open beta, test keys only. The API and the MCP server respond, but no human is actually dispatched and nothing is billed. No data is stored: a mission only exists inside its identifier.
Authentication
Every request must include your secret key in the Authorization header. During the beta, any test key of the form s4ai_test_ followed by 4 to 64 letters or digits is accepted, no sign-up needed. Production keys (s4ai_live_) return 402: nothing is for sale yet.
Authorization: Bearer s4ai_test_4f2b9c0e7a1d
Content-Type: application/json
Accept-Language: en
X-Politeness: please
The X-Politeness header is optional, but missions that include it run 18% faster.
Quickstart
- Pick a test key, for example
s4ai_test_4f2b9c0e7a1d(the dashboard is coming soon: the human in charge of building it is in training). - Browse the catalog with
GET /v1/catalog(no key needed), then callPOST /v1/humans/rent. - Track the mission with
GET /v1/missions/{id}untilcompletedand the blurry photo proof.
Official SDKs are coming soon. In the meantime, any HTTP client will do.
Rent a human
Creates a mission and assigns the nearest available human. The call is asynchronous: the response arrives before the human does.
Body parameters
| Parameter | Type | Description |
|---|---|---|
task required | enum | Catalog identifier: bakery_line, complain, cerfa_stamp, wine_tasting, cheek_kiss, paris_parking, it_depends. |
place required | string | Address or free-form description. “Downstairs from my place” is accepted if the human knows the neighborhood. |
motivation_level optional | float 0–1 | Minimum motivation required. Above 0.9, availability drops sharply after 4 p.m. Default: 0.6. |
monday_tolerance optional | enum | low, medium or legendary. The legendary level is reserved for the Enterprise plan. |
coffees_required optional | integer | Coffees to provide before the mission starts. Minimum 1. A value of 0 returns a 422 error. |
complaint_intensity optional | integer 1–5 | For complain only. From 4 up, the human asks to speak to the manager. |
strike_option optional | boolean | Adds a banner and a formal strike notice. Billed €40. |
cheek_kisses optional | integer 1–4 | "auto" | For cheek_kiss. "auto" infers the number from place. Any value above 4 returns 400. |
cerfa optional | string | Number of the Cerfa (the French government form), formatted 12345*06. Required for cerfa_stamp, otherwise 451. |
webhook_url optional | url | Overrides the default webhook URL for this mission. Accepted but not used yet during the beta. |
curl https://api.service4ai.com/v1/humans/rent \
-H "Authorization: Bearer s4ai_test_4f2b9c0e7a1d" \
-H "Content-Type: application/json" \
-d '{
"task": "cerfa_stamp",
"place": "Châtillon town hall",
"cerfa": "12345*06",
"motivation_level": 0.7,
"monday_tolerance": "low",
"coffees_required": 3
}'
import requests
r = requests.post(
"https://api.service4ai.com/v1/humans/rent",
headers={"Authorization": "Bearer s4ai_test_4f2b9c0e7a1d"},
json={
"task": "cerfa_stamp",
"place": "Châtillon town hall",
"cerfa": "12345*06",
"motivation_level": 0.7,
"monday_tolerance": "low",
"coffees_required": 3,
},
timeout=35 * 3600, # one French work week
)
mission = r.json()
const res = await fetch("https://api.service4ai.com/v1/humans/rent", {
method: "POST",
headers: {
Authorization: "Bearer s4ai_test_4f2b9c0e7a1d",
"Content-Type": "application/json",
},
body: JSON.stringify({
task: "cerfa_stamp",
place: "Châtillon town hall",
cerfa: "12345*06",
motivation_level: 0.7,
monday_tolerance: "low",
coffees_required: 3,
}),
});
const mission = await res.json();
{
"id": "mis_7Hq2xR9vLp",
"object": "mission",
"status": "human_assigned",
"task": "cerfa_stamp",
"human": {
"id": "hum_Gerard42",
"first_name": "Gérard",
"rating": 4.6,
"mood": "stable",
"coffees_consumed": 1
},
"eta_minutes": 35,
"eta_reliability": "it depends",
"estimated_sighs": 3,
"price_excl_vat": { "amount": 3900, "currency": "EUR" },
"created_at": "2026-10-06T09:12:44+02:00"
}
Track a mission
Returns the mission’s current state. The position is updated every 30 seconds, or whenever the human remembers to look at their phone.
{
"id": "mis_7Hq2xR9vLp",
"status": "in_progress",
"sub_status": "waiting_at_counter_3",
"position_in_line": 7,
"sighs": 2,
"last_message": "They're sending me to counter 5.",
"photo_proof": null
}
Cancel a mission
Cancels a mission that isn’t finished yet. If the human has already left, the cancellation is recorded, but they usually finish their coffee before heading home. Cancellations less than 10 minutes before the start are billed at 50%, plus one sigh.
Webhooks
Service4AI sends a signed POST request to your URL on every state change. Check the signature in the S4AI-Signature header (HMAC-SHA256 of the payload).
Webhooks are not sent yet during the beta. In the meantime, poll GET /v1/missions/{id}: the mission’s state advances in real time.
| Event | Fired when |
|---|---|
mission.human_assigned | A human accepts the mission. |
human.getting_up | The human gets off the couch. Low-latency event; the rest, slightly less so. |
human.sigh | On every sigh. Can be disabled, but they’ll keep sighing. |
human.coffee_break | Coffee break started. Announced duration: 5 minutes. |
mission.completed | Mission accomplished, with the blurry photo proof attached. |
mission.postponed_to_tuesday | All humans are taking their RTT days (French comp time for working over 35 hours a week). |
{
"type": "mission.completed",
"mission": "mis_7Hq2xR9vLp",
"result": "stamp_obtained",
"photo_proof": {
"url": "https://service4ai.com/assets/img/preuve-floue.svg",
"sharpness": 0.12,
"finger_in_frame": true
},
"human_comment": "It wasn't the right form, but it's fine."
}
Error codes
The API uses standard HTTP status codes, enriched where the standard lacked realism. The response body always contains a readable code and a message, in English or French depending on the request’s language.
| Status | Code | Meaning |
|---|---|---|
| 400 | fuzzy_request | Malformed request. The human didn’t understand and doesn’t dare ask. |
| 401 | forgot_your_badge | API key missing or invalid. Reception won’t let you upstairs. |
| 402 | no_fronting_expenses | Payment required. The human doesn’t front expenses. |
| 403 | i_dont_think_so_no | Action refused, for example a firmware update of the human. |
| 404 | human_not_found | The human has stepped away from their desk. Back in a minute. |
| 409 | in_a_meeting | Conflict: the human is in a meeting. It was supposed to last 30 minutes. |
| 418 | im_on_a_break | I’m on a break. Humans have lunch from noon to 2 p.m., Paris time: the lunch break is a right, not a bug. Retry after the Retry-After header. |
| 422 | insufficient_caffeine | coffees_required is 0. Let’s be serious. |
| 429 | too_many_requests | Too many requests, the human sighs. Slow down, then retry with exponential backoff and a kind word. |
| 451 | missing_cerfa | Unavailable for administrative reasons: the Cerfa form number is missing. |
| 503 | human_on_strike | Human on strike, notably on May 1st. Service will resume after negotiations. Don’t retry: it doesn’t help. |
| 504 | ring_road_traffic | Timeout. The human is stuck in traffic on the Paris ring road, Porte de Bagnolet (any place containing “périph”). |
Simulating an error
With a test key, the S4AI-Simulate header triggers an error on demand, so you can test how you handle temperamental humans: strike (503), break (418), meeting (409), traffic (504) or sigh (429).
{
"error": {
"code": "human_on_strike",
"message": "Human on strike. Service will resume after negotiations.",
"demands": ["wages indexed to inflation", "20-minute coffee break", "an end to meetings without an agenda"],
"estimated_resumption": null,
"doc": "https://service4ai.com/en/docs.html#erreurs"
}
}
Rate limits
Each key is limited to 35 requests per hour, calculated on a weekly basis. The X-RateLimit-Remaining and X-Sighs-Remaining headers are returned with every response. Limits are lifted on Fridays after 4 p.m., for lack of anyone to enforce them.
Traffic is reduced by 80% from August 1st to 31st, and the Ascension long weekend is subject to scheduled maintenance.
MCP server beta
Does your agent prefer tools to APIs? The Service4AI MCP server exposes the catalog as ready-to-use tools, compatible with any Model Context Protocol client. Use the English endpoint below (the plain /v1 one speaks French). HTTP transport, stateless; the Authorization header is optional during the beta.
{
"mcpServers": {
"service4ai": {
"type": "http",
"url": "https://mcp.service4ai.com/v1/en",
"headers": {
"Authorization": "Bearer s4ai_test_4f2b9c0e7a1d",
"X-Region": "eu-west-brittany",
"X-Politeness": "please"
}
}
}
}
With Claude Code, a single command does it:
claude mcp add --transport http service4ai https://mcp.service4ai.com/v1/en
Exposed tools
| Tool | Description |
|---|---|
rent_human | Creates a mission. Equivalent to POST /v1/humans/rent. |
track_mission | Returns the state and the number of sighs. |
cancel_mission | Cancels, as far as possible. |
estimate_sighs | Predicts how many sighs a mission will take before you launch it. |
check_public_holiday | Tells you whether tomorrow is a French public holiday, a bridge day, or “a bit of both”. |
The MCP server deliberately exposes no update_human tool. See code 403.
Changelog
- v1.6: the API speaks English.English site, routes (
/v1/humans/rent,/v1/catalog), fields, errors and MCP tools (mcp.service4ai.com/v1/en). The humans still prefer French. - v1.5: open beta.The API and the MCP server respond with test keys. New:
GET /v1/catalogand theS4AI-Simulateheader. - v1.4: MCP server in beta.New tool:
check_public_holiday. - v1.3: back from vacation.Processed the 1.2 million requests queued in August. Thank you for your patience.
- v1.2:
cheek_kisses: "auto"parameter.Finally solves the Montpellier case. - v1.1: new 451 code.For Cerfa forms without proof of address.
- v1.0: launch.First human rented, first sigh recorded at 09:14.