curl --request GET \
--url https://roughy-api-staging.fly.dev/v1/projects \
--header 'Authorization: Bearer <token>'import requests
url = "https://roughy-api-staging.fly.dev/v1/projects"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://roughy-api-staging.fly.dev/v1/projects', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://roughy-api-staging.fly.dev/v1/projects",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://roughy-api-staging.fly.dev/v1/projects"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://roughy-api-staging.fly.dev/v1/projects")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://roughy-api-staging.fly.dev/v1/projects")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_body{
"items": [
{
"created_at": "2026-05-02T08:54:52.423000Z",
"id": "019de7f5-7e21-7402-92a8-1c0e1fa84411",
"last_activity_at": "2026-05-14T17:31:08.902000Z",
"name": "Episode 42",
"state": "active",
"updated_at": "2026-05-02T08:54:52.423000Z"
}
],
"limit": 50,
"next_cursor": null
}{
"error": {
"code": "rate_limited",
"message": "Per-user rate limit exceeded; honour `Retry-After`."
}
}List projects
One page of your projects, most recently active first (keyset cursor
pagination). Ordering follows last_activity_at.
curl --request GET \
--url https://roughy-api-staging.fly.dev/v1/projects \
--header 'Authorization: Bearer <token>'import requests
url = "https://roughy-api-staging.fly.dev/v1/projects"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://roughy-api-staging.fly.dev/v1/projects', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://roughy-api-staging.fly.dev/v1/projects",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://roughy-api-staging.fly.dev/v1/projects"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://roughy-api-staging.fly.dev/v1/projects")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://roughy-api-staging.fly.dev/v1/projects")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_body{
"items": [
{
"created_at": "2026-05-02T08:54:52.423000Z",
"id": "019de7f5-7e21-7402-92a8-1c0e1fa84411",
"last_activity_at": "2026-05-14T17:31:08.902000Z",
"name": "Episode 42",
"state": "active",
"updated_at": "2026-05-02T08:54:52.423000Z"
}
],
"limit": 50,
"next_cursor": null
}{
"error": {
"code": "rate_limited",
"message": "Per-user rate limit exceeded; honour `Retry-After`."
}
}Authorizations
Pass your API key as Authorization: Bearer sk_…. Mint a key from your dashboard's API-keys page.
Query Parameters
Maximum number of items to return (1-100). Defaults to 20.
1 <= x <= 100Opaque continuation token from the previous page's next_cursor. Omit for the first page.
Filter by lifecycle state. Defaults to active.
active, archived Response
One page of projects, most recently active first.
One page of projects, most recently active first (keyset cursor pagination).
One page of items, ordered by this list's sort key descending. See the endpoint description for which key that is.
Show child attributes
Show child attributes
The page-size limit this response was computed with.
Opaque continuation token. Pass as cursor on the next request to fetch the following page; null means this is the last page.