Admin API
The extension adds routes to the Otoroshi admin API, under
/api/extensions/cloud-apim/extensions/clevercloud-reaper. They take the same credentials as the
rest of the admin API: an admin apikey, with Basic auth or the Otoroshi-Client-Id /
Otoroshi-Client-Secret headers.
export OTO=http://otoroshi-api.oto.tools:8080
export AUTH='admin-api-apikey-id:admin-api-apikey-secret'
export REAPER=$OTO/api/extensions/cloud-apim/extensions/clevercloud-reaper
The actions (_wake, _reap, _reset) must reach a leader: workers answer them with a 400.
List the apps
curl -u $AUTH $REAPER/apps
Every app the reaper manages, with its state:
[
{
"app_id": "app_0f4c2b0e-1a2b-4c3d-8e9f-0123456789ab",
"status": "Up",
"owner_id": "orga_7d2a6c0e-5b1f-4e2d-9a8b-0123456789ab",
"name": "my-staging-app",
"clever_state": "SHOULD_BE_UP",
"cause": "the app is up",
"error_cause": null,
"last_status_update": 1791216000000,
"last_up_at": 1791216000000,
"last_down_at": 1791212400000,
"action_at": 1791215940000,
"last_check_at": 1791216300000,
"routes": ["route_3f1c0a9e-6b2d-4e7f-8a9b-0123456789ab"],
"grace_period": 3600000,
"fail_timeout": 900000,
"last_access": 1791216240000,
"reap_at": 1791219840000
}
]
| Field | |
|---|---|
status | WaitingForInit, Up, WaitingForShutdown, Down, WaitingForUp or Error |
clever_state | the state Clever Cloud reported at the last check |
cause | why the app is in its state |
error_cause | why it is in error, when it is |
last_status_update | when the state last changed |
last_up_at, last_down_at | when it last became Up, Down |
action_at | when the reaper last asked Clever Cloud to stop or start it, while it waits for the result |
last_check_at | when the reaper last looked at it |
routes | the routes that manage it |
grace_period, fail_timeout | the ones in force, the longest of its routes, in milliseconds |
last_access | its last access, from any route and any node |
reap_at | when it will be put to sleep if nothing happens, while it is Up |
Every date is in epoch milliseconds.
Read one app
curl -u $AUTH $REAPER/apps/app_0f4c2b0e-1a2b-4c3d-8e9f-0123456789ab
The same object, or a 404 when the reaper does not manage the app.
Read the history of an app
curl -u $AUTH "$REAPER/apps/app_0f4c2b0e-1a2b-4c3d-8e9f-0123456789ab/history?page=1&page_size=20"
The transitions, latest first. page starts at 1, page_size is 20 by default and 500 at most.
[
{
"app_id": "app_0f4c2b0e-1a2b-4c3d-8e9f-0123456789ab",
"from": "WaitingForUp",
"to": "Up",
"cause": "the app is up",
"at": 1791216000000
},
{
"app_id": "app_0f4c2b0e-1a2b-4c3d-8e9f-0123456789ab",
"from": "Down",
"to": "WaitingForUp",
"cause": "a request needs the app",
"at": 1791215940000
}
]
Wake an app up
curl -u $AUTH -X POST $REAPER/apps/app_0f4c2b0e-1a2b-4c3d-8e9f-0123456789ab/_wake
Starts the app if it sleeps, exactly as a request would, and answers with its state. It is a no-op on
an app that is up. 404 when the reaper does not manage the app.
Put an app to sleep
curl -u $AUTH -X POST $REAPER/apps/app_0f4c2b0e-1a2b-4c3d-8e9f-0123456789ab/_reap
Stops the app now, whatever its traffic, and answers with its new state, WaitingForShutdown. The
history records put to sleep by apikey <name>. A 409 when the app is not Up, is not
SHOULD_BE_UP on Clever Cloud, or is busy with another operation.
Reset an app in error
curl -u $AUTH -X POST $REAPER/apps/app_0f4c2b0e-1a2b-4c3d-8e9f-0123456789ab/_reset
Puts the app back in WaitingForInit: its state is read from Clever Cloud again at the next run of
the job. Works from any state, not only Error.
Savings
curl -u $AUTH $REAPER/savings
What the sleeps saved for the whole install, the ones still running included. Amounts are in
currency, rounded to four decimals.
{
"enabled": true,
"currency": "EUR",
"total": 412.8731,
"today": 3.2104,
"this_month": 61.5502,
"this_year": 398.0412,
"asleep": 7,
"saving_per_hour": 0.6444,
"apps_with_cost": 12,
"last_30_days": [{ "date": "2026-09-07", "saved": 1.9301 }, "..."],
"last_12_months": [{ "month": "2025-11", "saved": 12.4410 }, "..."]
}
| Field | |
|---|---|
asleep | the apps the reaper put to sleep that sleep right now |
saving_per_hour | what those apps would cost per hour if they ran |
apps_with_cost | the apps whose cost is known |
curl -u $AUTH $REAPER/apps/app_0f4c2b0e-1a2b-4c3d-8e9f-0123456789ab/savings
The same for one app, with its cost and its sleeps:
{
"enabled": true,
"app_id": "app_0f4c2b0e-1a2b-4c3d-8e9f-0123456789ab",
"currency": "EUR",
"cost": {
"zone": "par",
"min_flavor": "M", "min_instances": 2, "hourly_min": 0.2111,
"max_flavor": "L", "max_instances": 4, "hourly_max": 0.8444,
"refreshed_at": 1791216000000
},
"total": 58.2214,
"slept_hours": 275.8,
"sleeps": 19,
"current": { "since": 1791190000000, "saved": 1.5247 },
"last_sleep": { "from": 1791100000000, "to": 1791150000000, "hours": 13.89, "hourly": 0.2111, "saved": 2.9319 },
"today": 0.4573, "this_month": 7.3007, "this_year": 58.2214,
"last_30_days": [{ "date": "2026-09-07", "saved": 0.2111 }, "..."]
}
cost is null until the size of the app has been read; current is null when the app is not
asleep. See Savings for what is counted.
Cluster plumbing
PUT /api/extensions/cloud-apim/extensions/clevercloud-reaper/cluster/access is how workers push
their last accesses to the leaders: a JSON object of app ids to epoch milliseconds. It is not meant
to be called by hand.
Configuring routes
The settings of the reaper are in the routes. Use the regular routes API of Otoroshi to change
them: the plugin is a slot of plugins, with the identifier and the configuration described in the
plugin reference.