Skip to content

Create a pricing policy

POST
/strategy/policies
curl --request POST \
--url https://api.flotera.com/api/v1/strategy/policies \
--header 'Content-Type: application/json' \
--cookie __Host-erm_session=<__Host-erm_session> \
--data '{ "name": "example", "preset": "max_profit", "gpu_model": "example", "marketplace": "vast", "pause_below_reliability": 1, "never_raise_when_rented": true, "offset_fraction": "12.340000", "max_usd_per_gpu_hour": "example" }'
Idempotency-Key
string
>= 1 characters <= 128 characters /^[\x21-\x7E]{1,128}$/

Idempotency key, 1–128 ASCII, unique per (tenant_id, operation, key) for at least 24 hours. Retrying with the same body replays the stored response; a different body returns 409 idempotency_conflict.

Media typeapplication/json
object
name
required
string
>= 1 characters <= 80 characters
preset
required

Which point of the market the policy aims at. mining_first and long_rentals_only are kept in the vocabulary but cannot be computed from market data alone — see computable on the policy. Dropping them would be cleaner code and worse product: someone who picked “Mining First” should learn what is missing, not find the option gone.

string
Allowed values: max_profit max_utilization mining_first long_rentals_only balanced custom
gpu_model
required

Card class the rule governs. One rule per card class and marketplace: two rules over the same cards would produce two prices, and which one wins would depend on the sweep order.

string
>= 1 characters <= 80 characters
marketplace
required

Supported marketplace. The database constrains the same two values, so a third one is a migration rather than a new string.

string
Allowed values: vast clore
pause_below_reliability

Reliability floor below which the rule stays silent. Omitted keeps the previous value when editing, and on creation takes the default of THIS marketplace — 0.900 on Vast, none on Clore. null turns the gate off.

number | null
<= 1
never_raise_when_rented

Defaults to true. Raising the price of a machine with a running rental ends its extension at the current term.

boolean
offset_fraction

Offset from the market anchor as a FRACTION: 0.10 is ten percent above. A fraction here and a percent elsewhere is an error by exactly one hundred, and it shows up as a price on a marketplace.

string
/^-?[0-9]+(\.[0-9]{1,6})?$/
max_usd_per_gpu_hour

Price ceiling. Not about greed — it catches 10 typed where 0.10 was meant, which would otherwise reach the marketplace.

string | null
/^-?[0-9]+(\.[0-9]{1,6})?$/

Created.

Media typeapplication/json
object
id
required

UUID (v7 for new entities; v4 accepted during migration).

string format: uuid
name
required
string
<= 80 characters
preset
required

Which point of the market the policy aims at. mining_first and long_rentals_only are kept in the vocabulary but cannot be computed from market data alone — see computable on the policy. Dropping them would be cleaner code and worse product: someone who picked “Mining First” should learn what is missing, not find the option gone.

string
Allowed values: max_profit max_utilization mining_first long_rentals_only balanced custom
gpu_model
required

The card class this rule governs, as the market rows key it (rtx 3060). Price is set per card class, not per machine: two 3060s in one rack are worth the same, a 4090 is not.

string
<= 80 characters
marketplace
required

Supported marketplace. The database constrains the same two values, so a third one is a migration rather than a new string.

string
Allowed values: vast clore
offset_fraction
required

Decimal value serialized as a string, never a JSON number.

string
/^-?[0-9]+(\.[0-9]{1,6})?$/
max_usd_per_gpu_hour

Decimal string or null when unknown.

string | null
/^-?[0-9]+(\.[0-9]{1,6})?$/
pause_below_reliability

Stay silent while the marketplace reliability of a machine is below this fraction. On Vast, under the platform threshold the machine is not shown to renters at all, so no price sells it — a suggestion there would optimise the price of goods absent from the shelf. Clore publishes no such threshold and a freshly joined machine reads near zero, so a new Clore rule starts with no floor. null disables the gate; that is a choice, not missing data.

number | null
<= 1
never_raise_when_rented
required

Never propose a price above the current one while a rental is running. Rental terms freeze at the moment of rent and extension is possible only while the offer is not dearer than the contract, so a raise quietly ends the extension: the renter finishes the term and leaves.

boolean
servers
required

How many machines the scope currently covers.

integer
computable
required

Whether this preset can be computed from market data today. False means the engine will produce nothing for it and says so, rather than silently suggesting nothing — silence reads as “all good”.

boolean
missing_input

What the preset needs and the platform does not have.

string | null
<= 200 characters
created_at
required

RFC 3339 UTC with microsecond precision.

string format: date-time
updated_at
required

RFC 3339 UTC with microsecond precision.

string format: date-time
Example
{
"preset": "max_profit",
"marketplace": "vast",
"offset_fraction": "12.340000",
"created_at": "2026-07-25T10:15:30.123456Z",
"updated_at": "2026-07-25T10:15:30.123456Z"
}

Missing/invalid credentials (code=unauthorized).

Media typeapplication/problem+json

RFC 9457 problem document with a stable machine code.

object
type
required
string format: uri
title
required
string
<= 256 characters
status
required
integer
>= 100 <= 599
code
required

Stable machine-readable error code (03 §2.4).

string
Allowed values: unauthorized forbidden csrf_rejected not_found conflict idempotency_conflict validation_failed rate_limited payload_too_large unsupported_agent_version temporarily_unavailable offline_queue_full online_queue_full plan_required server_limit_reached feature_not_entitled account_in_grace account_frozen payment_pending payment_expired payment_amount_mismatch change_already_pending change_already_applied change_effective reserve_not_covered direction_changed
detail
string
<= 2048 characters
instance
string
<= 512 characters
request_id

UUID (v7 for new entities; v4 accepted during migration).

string format: uuid
errors
Array<object>
<= 100 items
object
path
required

JSON Pointer to the offending field.

string
<= 512 characters
code
required
string
<= 64 characters
Example
{
"type": "https://ermeon.com/problems/validation",
"code": "unauthorized"
}

Authenticated but not permitted. code=forbidden — role/scope mismatch; code=feature_not_entitled — the plan does not include the capability; code=account_frozen — the account is frozen and this operation is declared x-ermeon-frozen: deny. The three are deliberately distinct: only the last one is fixed by a top-up (13 §5.6).

Media typeapplication/problem+json

RFC 9457 problem document with a stable machine code.

object
type
required
string format: uri
title
required
string
<= 256 characters
status
required
integer
>= 100 <= 599
code
required

Stable machine-readable error code (03 §2.4).

string
Allowed values: unauthorized forbidden csrf_rejected not_found conflict idempotency_conflict validation_failed rate_limited payload_too_large unsupported_agent_version temporarily_unavailable offline_queue_full online_queue_full plan_required server_limit_reached feature_not_entitled account_in_grace account_frozen payment_pending payment_expired payment_amount_mismatch change_already_pending change_already_applied change_effective reserve_not_covered direction_changed
detail
string
<= 2048 characters
instance
string
<= 512 characters
request_id

UUID (v7 for new entities; v4 accepted during migration).

string format: uuid
errors
Array<object>
<= 100 items
object
path
required

JSON Pointer to the offending field.

string
<= 512 characters
code
required
string
<= 64 characters
Example
{
"type": "https://ermeon.com/problems/validation",
"code": "unauthorized"
}

A policy with that name already exists.

Media typeapplication/problem+json

RFC 9457 problem document with a stable machine code.

object
type
required
string format: uri
title
required
string
<= 256 characters
status
required
integer
>= 100 <= 599
code
required

Stable machine-readable error code (03 §2.4).

string
Allowed values: unauthorized forbidden csrf_rejected not_found conflict idempotency_conflict validation_failed rate_limited payload_too_large unsupported_agent_version temporarily_unavailable offline_queue_full online_queue_full plan_required server_limit_reached feature_not_entitled account_in_grace account_frozen payment_pending payment_expired payment_amount_mismatch change_already_pending change_already_applied change_effective reserve_not_covered direction_changed
detail
string
<= 2048 characters
instance
string
<= 512 characters
request_id

UUID (v7 for new entities; v4 accepted during migration).

string format: uuid
errors
Array<object>
<= 100 items
object
path
required

JSON Pointer to the offending field.

string
<= 512 characters
code
required
string
<= 64 characters
Example
{
"type": "https://ermeon.com/problems/validation",
"code": "unauthorized"
}

Request failed validation (code=validation_failed), with per-field errors.

Media typeapplication/problem+json

RFC 9457 problem document with a stable machine code.

object
type
required
string format: uri
title
required
string
<= 256 characters
status
required
integer
>= 100 <= 599
code
required

Stable machine-readable error code (03 §2.4).

string
Allowed values: unauthorized forbidden csrf_rejected not_found conflict idempotency_conflict validation_failed rate_limited payload_too_large unsupported_agent_version temporarily_unavailable offline_queue_full online_queue_full plan_required server_limit_reached feature_not_entitled account_in_grace account_frozen payment_pending payment_expired payment_amount_mismatch change_already_pending change_already_applied change_effective reserve_not_covered direction_changed
detail
string
<= 2048 characters
instance
string
<= 512 characters
request_id

UUID (v7 for new entities; v4 accepted during migration).

string format: uuid
errors
Array<object>
<= 100 items
object
path
required

JSON Pointer to the offending field.

string
<= 512 characters
code
required
string
<= 64 characters
Example
{
"type": "https://ermeon.com/problems/validation",
"code": "unauthorized"
}

A dependency the endpoint needs is not configured or is temporarily unavailable (code=unavailable). The rest of the API keeps working — an absent external integration must not take the service down.

Media typeapplication/problem+json

RFC 9457 problem document with a stable machine code.

object
type
required
string format: uri
title
required
string
<= 256 characters
status
required
integer
>= 100 <= 599
code
required

Stable machine-readable error code (03 §2.4).

string
Allowed values: unauthorized forbidden csrf_rejected not_found conflict idempotency_conflict validation_failed rate_limited payload_too_large unsupported_agent_version temporarily_unavailable offline_queue_full online_queue_full plan_required server_limit_reached feature_not_entitled account_in_grace account_frozen payment_pending payment_expired payment_amount_mismatch change_already_pending change_already_applied change_effective reserve_not_covered direction_changed
detail
string
<= 2048 characters
instance
string
<= 512 characters
request_id

UUID (v7 for new entities; v4 accepted during migration).

string format: uuid
errors
Array<object>
<= 100 items
object
path
required

JSON Pointer to the offending field.

string
<= 512 characters
code
required
string
<= 64 characters
Example
{
"type": "https://ermeon.com/problems/validation",
"code": "unauthorized"
}