Skip to main content

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
statusWaitingForInit, Up, WaitingForShutdown, Down, WaitingForUp or Error
clever_statethe state Clever Cloud reported at the last check
causewhy the app is in its state
error_causewhy it is in error, when it is
last_status_updatewhen the state last changed
last_up_at, last_down_atwhen it last became Up, Down
action_atwhen the reaper last asked Clever Cloud to stop or start it, while it waits for the result
last_check_atwhen the reaper last looked at it
routesthe routes that manage it
grace_period, fail_timeoutthe ones in force, the longest of its routes, in milliseconds
last_accessits last access, from any route and any node
reap_atwhen 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
asleepthe apps the reaper put to sleep that sleep right now
saving_per_hourwhat those apps would cost per hour if they ran
apps_with_costthe 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.