Provides a simple feature toggle API that supports strings as keys and stringified booleans ("true"
or "false"
) as values.
Features can be given an optional start and end date.
Features are grouped by prepending UUIDs. This is done automatically on creating the first feature in a group. To add more features to the group, prepend the new feature's key with a UUIDv4 followed by a pipe symbol |
(see examples)
All endpoints apart from the GET
endpoint require a secret. This is created when creating a new feature toggle without a UUIDv4 and returned from the POST
request. The secret is only returned upon creating the first feature toggle in a group.
Please note that this program is in an alpha state and has not been tested. Use at your own risk!
Copy and adapt docker-compose.yml
or build your own setup.
docker compose -f docker-compose-local.yml up --force-recreate --build
curl -d '{"Key":"myKey","Value":"true"}' -X POST "http://127.0.0.1:8080/features"
successful response:
{"activeAt":null,"disabledAt":null,"key":"896ea308-382f-46b0-bc59-d93a28013633|myKey","secret":"156152c0-07c6-4c87-b73a-b10db750bca3aa88c846-ce3f-48af-8fc0-e42a7b92f7321c8af6bc-b8a8-4bd8-88a5-53215bb82ae9","value":"true"}
error response:
{"error":"Failed to create feature toggle"}
curl -d '{"Key":"896ea308-382f-46b0-bc59-d93a28013633|myOtherKey","Value":"true","Secret":"156152c0-07c6-4c87-b73a-b10db750bca3aa88c846-ce3f-48af-8fc0-e42a7b92f7321c8af6bc-b8a8-4bd8-88a5-53215bb82ae9"}' -X POST "http://127.0.0.1:8080/features"
successful response:
{"activeAt":null,"disabledAt":null,"key":"896ea308-382f-46b0-bc59-d93a28013633|myOtherKey","value":"true"}
error response if secret is wrong:
{"error":"Invalid secret"}
error response if secret is correct but key exists:
{"error":"Failed to create feature toggle"}
curl -X DELETE "http://127.0.0.1:8080/features/896ea308-382f-46b0-bc59-d93a28013633|myKey/156152c0-07c6-4c87-b73a-b10db750bca3aa88c846-ce3f-48af-8fc0-e42a7b92f7321c8af6bc-b8a8-4bd8-88a5-53215bb82ae9"
successful response:
{"message":"Feature toggle deleted"}
error response if secret is wrong:
{"error":"Invalid secret"}
error response if secret is correct but feature was not found:
{"error":"Feature not found"}
curl -X PUT "http://127.0.0.1:8080/features/activate/896ea308-382f-46b0-bc59-d93a28013633|myKey/156152c0-07c6-4c87-b73a-b10db750bca3aa88c846-ce3f-48af-8fc0-e42a7b92f7321c8af6bc-b8a8-4bd8-88a5-53215bb82ae9"
successful response:
{"activeAt":null,"disabledAt":null,"key":"896ea308-382f-46b0-bc59-d93a28013633|myKey","value":"true"}
error response if secret is wrong:
{"error":"Invalid secret"}
error response if secret is correct but feature was not found:
{"error":"Failed to activate feature toggle"}
curl -X PUT "http://127.0.0.1:8080/features/activateAt/896ea308-382f-46b0-bc59-d93a28013633|myKey/2026-10-10/156152c0-07c6-4c87-b73a-b10db750bca3aa88c846-ce3f-48af-8fc0-e42a7b92f7321c8af6bc-b8a8-4bd8-88a5-53215bb82ae9"
successful response:
{"activeAt":2026-10-10,"disabledAt":null,"key":"896ea308-382f-46b0-bc59-d93a28013633|myKey","value":"true"}
error response if secret is wrong:
{"error":"Invalid secret"}
error response if secret is correct but feature was not found:
{"error":"Failed to activate feature toggle at"}
curl -X PUT "http://127.0.0.1:8080/features/deactivate/896ea308-382f-46b0-bc59-d93a28013633|myKey/156152c0-07c6-4c87-b73a-b10db750bca3aa88c846-ce3f-48af-8fc0-e42a7b92f7321c8af6bc-b8a8-4bd8-88a5-53215bb82ae9"
successful response:
{"activeAt":null,"disabledAt":null,"key":"88ce4805-92a5-4774-ac05-5ebf12de9a58|a","value":"false"}
error response if secret is wrong:
{"error":"Invalid secret"}
error response if secret is correct but feature was not found:
{"error":"Failed to deactivate feature toggle"}
curl -X PUT "http://127.0.0.1:8080/features/deactivateAt/896ea308-382f-46b0-bc59-d93a28013633|myKey/2026-10-10/156152c0-07c6-4c87-b73a-b10db750bca3aa88c846-ce3f-48af-8fc0-e42a7b92f7321c8af6bc-b8a8-4bd8-88a5-53215bb82ae9"
successful response:
{"activeAt":null,"disabledAt":2026-10-10,"key":"88ce4805-92a5-4774-ac05-5ebf12de9a58|a","value":"false"}
error response if secret is wrong:
{"error":"Invalid secret"}
error response if secret is correct but feature was not found:
{"error":"Failed to deactivate feature toggle"}
curl "http://127.0.0.1:8080/features/896ea308-382f-46b0-bc59-d93a28013633|myKey"
successful response:
{"activeAt":null,"disabledAt":null,"key":"896ea308-382f-46b0-bc59-d93a28013633|myKey","value":"true"}
error response:
{"error":"Feature not found"}
curl "http://127.0.0.1:8080/features/896ea308-382f-46b0-bc59-d93a28013633"
successful response:
{"toggles":[{"ID":20,"Key":"896ea308-382f-46b0-bc59-d93a28013633|myKey","Value":"true","ActiveAt":null,"DisabledAt":null},{"ID":21,"Key":"896ea308-382f-46b0-bc59-d93a28013633|myOtherKey","Value":"true","ActiveAt":null,"DisabledAt":null}]}
curl "http://127.0.0.1:8080/collectionHash/896ea308-382f-46b0-bc59-d93a28013633"
successful response:
{"collectionHash":"dce01876b3f0c843fb2c1e5efe54bf807dc991eefc660d112306b49f6e2335c6"}
error response:
{"error":"Feature not found"}
curl -X PUT "http://127.0.0.1:8080/secret/update/896ea308-382f-46b0-bc59-d93a28013633/156152c0-07c6-4c87-b73a-b10db750bca3aa88c846-ce3f-48af-8fc0-e42a7b92f7321c8af6bc-b8a8-4bd8-88a5-53215bb82ae9/mynewsecret"
successful response:
{"key":"896ea308-382f-46b0-bc59-d93a28013633"}
error response if secret is invalid or UUID does not exist:
{"error":"Invalid secret"}
error response if new secret is not URL parseable:
{"error": "New secret is not URL parseable, aborting operation"}