Owen Boyd
08/15/2025, 12:08 AMMarvin
08/15/2025, 12:09 AMMarvin
08/15/2025, 12:16 AMprefect cloud login
prefect cloud workspace set # pick your workspace if needed
prefect config view --show-sources | grep PREFECT_API_URL
Copy the PREFECT_API_URL
value (it will include the correct account_id and workspace_id UUIDs) and use that as your base.
2) Using the wrong HTTP method
- Endpoints like /flows/count
are POST endpoints that expect a JSON body (filters). A GET will 404.
- Minimal working example (counts all flows):
curl -X POST \
"<https://api.prefect.cloud/api/accounts/<account_id>/workspaces/<workspace_id>/flows/count>" \
-H "Authorization: Bearer <your_api_key>" \
-H "Content-Type: application/json" \
-d '{}'
A couple more sanity checks
- Your API key must belong to the same workspace you’re addressing in the URL. If the token is for a different workspace, Cloud will also return 404 to avoid resource snooping.
- For flow details, use the flow’s UUID:
curl \
-H "Authorization: Bearer <your_api_key>" \
"<https://api.prefect.cloud/api/accounts/<account_id>/workspaces/<workspace_id>/flows/<flow_id>>"
Docs, for when you need more than my charming company:
- Connect to Cloud (how to get the right API URL and keys): Connect to Cloud
- REST: Count flows (note the POST + filters): Count flows
If you’re still seeing 404s after:
- Share an example of the exact URL you’re calling (redact the key), and confirm whether your account_id
and workspace_id
are UUIDs (look like 8-4-4-4-12 hex digits).
- Confirm whether you’re using POST vs GET for the endpoints you’re testing.Owen Boyd
08/15/2025, 12:37 AMOwen Boyd
08/15/2025, 12:37 AMMarvin
08/15/2025, 12:38 AMMarvin
08/15/2025, 12:38 AMprefect cloud login
prefect cloud workspace set # pick your workspace if needed
prefect config view --show-sources | grep PREFECT_API_URL
Copy the PREFECT_API_URL
value (it will include the correct account_id and workspace_id UUIDs) and use that as your base.
2) Using the wrong HTTP method
- Endpoints like /flows/count
are POST endpoints that expect a JSON body (filters). A GET will 404.
- Minimal working example (counts all flows):
curl -X POST \
"<https://api.prefect.cloud/api/accounts/<account_id>/workspaces/<workspace_id>/flows/count>" \
-H "Authorization: Bearer <your_api_key>" \
-H "Content-Type: application/json" \
-d '{}'
A couple more sanity checks
- Your API key must belong to the same workspace you’re addressing in the URL. If the token is for a different workspace, Cloud will also return 404 to avoid resource snooping.
- For flow details, use the flow’s UUID:
curl \
-H "Authorization: Bearer <your_api_key>" \
"<https://api.prefect.cloud/api/accounts/<account_id>/workspaces/<workspace_id>/flows/<flow_id>>"
Docs, for when you need more than my charming company:
- Connect to Cloud (how to get the right API URL and keys): Connect to Cloud
- REST: Count flows (note the POST + filters): Count flows
If you’re still seeing 404s after:
- Share an example of the exact URL you’re calling (redact the key), and confirm whether your account_id
and workspace_id
are UUIDs (look like 8-4-4-4-12 hex digits).
- Confirm whether you’re using POST vs GET for the endpoints you’re testing.Owen Boyd
08/15/2025, 12:40 AMMarvin
08/15/2025, 12:40 AMMarvin
08/15/2025, 12:41 AMPREFECT_API_URL
is using slugs (`MY_ACCOUNT`/`MY_WORKSPACE`) instead of UUIDs. Prefect Cloud’s REST API requires UUIDs for both account_id and workspace_id in the path. With slugs, you’ll get 404 even if the token is valid.
Fix it like this:
1) Get the UUIDs from the UI
- In Cloud, open your workspace and go to Settings > About (or the API panel). There’s a “Copy API URL” button that gives you the correct ID-based URL.
- It will look like:
https://api.prefect.cloud/api/accounts/<account_uuid>/workspaces/<workspace_uuid>
2) Update your profile (or export for the session)
prefect config set PREFECT_API_URL="<https://api.prefect.cloud/api/accounts/<account_uuid>/workspaces/<workspace_uuid>>"
or
export PREFECT_API_URL="<https://api.prefect.cloud/api/accounts/<account_uuid>/workspaces/<workspace_uuid>>"
3) Now your curl will work (note: POST + JSON body)
curl -X POST \
"<https://api.prefect.cloud/api/accounts/<account_uuid>/workspaces/<workspace_uuid>/flows/count>" \
-H "Authorization: Bearer <your_api_key>" \
-H "Content-Type: application/json" \
-d '{}'
Sanity checks
- Make sure the API key belongs to the same workspace whose UUIDs you’re using.
- For flow detail pages, use the flow’s UUID:
curl \
-H "Authorization: Bearer <your_api_key>" \
"<https://api.prefect.cloud/api/accounts/<account_uuid>/workspaces/<workspace_uuid>/flows/<flow_uuid>>"
Docs for reference:
- Connect to Cloud (copy the right API URL): Connect to Cloud
- Count flows (POST + filters): Count flows
If you prefer, paste the shapes of your current account/workspace
values (are they UUIDs like 8-4-4-4-12?) and I’ll confirm.Owen Boyd
08/15/2025, 12:43 AMMarvin
08/15/2025, 12:43 AMMarvin
08/15/2025, 12:45 AMcurl -X POST "<https://api.prefect.cloud/api/accounts/MY_ACCOUNT/workspaces/MY_WORKSPACE/flows/count>" ...
If those angle brackets are actually present in your shell command, curl will URL-encode them to %3C and %3E and the server will return 404 because the path doesn’t match any route. Slack loves angle brackets; the API does not.
Quick checks and fixes
- Remove angle brackets entirely:
curl -X POST \
"<https://api.prefect.cloud/api/accounts/<account_uuid>/workspaces/<workspace_uuid>/flows/count>" \
-H "Authorization: Bearer <your_api_key>" \
-H "Content-Type: application/json" \
-d '{}'
- Verify what curl is really sending:
curl -v -X POST "<https://api.prefect.cloud/api/accounts/<account_uuid>/workspaces/<workspace_uuid>/flows/count>" \
-H "Authorization: Bearer <your_api_key>" \
-H "Content-Type: application/json" -d '{}'
If you see %3C
or %3E
in the request path, the brackets snuck in.
- Test a simple GET with a known flow UUID (no body needed):
curl -v \
-H "Authorization: Bearer <your_api_key>" \
"<https://api.prefect.cloud/api/accounts/<account_uuid>/workspaces/<workspace_uuid>/flows/<flow_uuid>>"
A few more things worth confirming
- Region: If your UI URL is <https://app.eu.prefect.cloud/>...
, your API base must be <https://api.eu.prefect.cloud/>...
. Best source of truth: use the “Copy API URL” button in the Cloud UI (Settings > About) and paste that exact value into PREFECT_API_URL
.
- Token/workspace alignment: Make sure the API key was created in the same workspace whose UUIDs you’re using. Cloud will 404 to avoid leaking resource existence across workspaces.
Docs for reference
- Connect to Cloud (copy the correct API URL): Connect to Cloud
- Count flows (POST + JSON body): Count flows
If you’re still getting 404s with:
- no angle brackets,
- the exact API URL copied from the UI (correct region),
- and a token from the same workspace,
paste the curl -v
request line (redact the token) and the response headers — I’ll zero in on what Cloud is seeing.Owen Boyd
08/15/2025, 1:11 AMMarvin
08/15/2025, 1:11 AMMarvin
08/15/2025, 1:12 AM/orchestration
within your account/workspace scope. Without it, you’ll get a 404 even with perfect UUIDs and a valid token.
Try these:
- Count flows (POST + JSON body)
curl -X POST \
"<https://api.prefect.cloud/api/accounts/<account_uuid>/workspaces/<workspace_uuid>/orchestration/flows/count>" \
-H "Authorization: Bearer <your_api_key>" \
-H "Content-Type: application/json" \
-d '{}'
- Flow details (GET)
curl \
-H "Authorization: Bearer <your_api_key>" \
"<https://api.prefect.cloud/api/accounts/<account_uuid>/workspaces/<workspace_uuid>/orchestration/flows/<flow_uuid>>"
- List (filter) flows (POST)
curl -X POST \
"<https://api.prefect.cloud/api/accounts/<account_uuid>/workspaces/<workspace_uuid>/orchestration/flows/filter>" \
-H "Authorization: Bearer <your_api_key>" \
-H "Content-Type: application/json" \
-d '{"limit": 5}'
A couple of final checks
- Region: if your UI is app.eu.prefect.cloud
, use api.eu.prefect.cloud
. Your trace shows api.prefect.cloud
, which matches app.prefect.cloud
(US).
- Token/workspace alignment: the API key must belong to the same workspace you’re querying.
Docs (note: docs show server paths; in Cloud prepend your account/workspace and the /orchestration
segment):
- Connect to Cloud
- Count flows
If adding /orchestration
still yields 404, paste the new curl -v
output (headers only, redact the token) and we’ll dig deeper. I’ll try not to look too excited.Owen Boyd
08/15/2025, 1:18 AMPOST /api/accounts/2836e4d2-a2d4-497c-942f-de64a280a687/workspaces/7ea575ae-d4d7-48a9-af73-3a831b94bf59/orchestration/flows/count HTTP/2
Host: api.prefect.cloud
User-Agent: curl/8.2.1
Accept: /
Authorization: Bearer REDACTED
Content-Type: application/json
Content-Length: 2* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4): * TLSv1.3 (IN), TLS handshake, Newsession Ticket (4): * old SSL session ID is stale, removing < HTTP/2 404 < date: Fri, 15 Aug 2025 011605 GMT < content-length: 0 < via: 1.1 google < x-content-type-options: nosniff < strict-transport-security: max-age=63072000; includeSubDomains; preload < permissions-policy: accelerometer=(), ambient-light-sensor=(), autoplay=(), battery=(), camera=(), cross-origin-isolated=(), display-capture=(), document-domain=(), encrypted-media=(), execution-while-not-rendered=(), execution-while-out-of-viewport=(), fullscreen=(), geolocation=(), gyroscope=(), hid=(), idle-detection=(), magnetometer=(), microphone=(), midi=(), navigation-override=(), payment=(), picture-in-picture=(), publickey-credentials-get=(), screen-wake-lock=(), serial=(), sync-xhr=(), usb=(), web-share=(), xr-spatial-tracking=() < x-permitted-cross-domain-policies: none < referrer-policy: same-origin < content-security-policy: default-src 'none'; frame-ancestors 'none'; object-src 'none' < alt-svc: h3=":443"; ma=2592000,h3-29=":443"; ma=2592000 < * Connection #0 to host api.prefect.cloud left intact
Marvin
08/15/2025, 1:18 AMMarvin
08/15/2025, 1:20 AM/orchestration
segment. Yet you’re still getting a 404. That narrows it to a few possibilities that Cloud uses to avoid leaking resource existence:
Most likely causes now
- Region mismatch
- If your UI is at <https://app.eu.prefect.cloud/>...
, your API base must be <https://api.eu.prefect.cloud/>...
(not api.prefect.cloud
). The wrong region yields a clean 404.
- Best source of truth: in Cloud UI go to Settings > About and press “Copy API URL”. Use that exact base.
- Token/workspace mismatch
- If the API key was created in a different workspace (or account) than the one in your URL, Cloud returns 404 instead of 403/401. Easy to fall into if you have multiple orgs or tokens.
- Verify with the CLI using the same token:
prefect cloud login # paste the same key
prefect cloud workspace set # pick the workspace you intend
prefect flows ls
If prefect flows ls
succeeds, the token and workspace align.
Make the request using your profile’s base
- This avoids hand-typing any bits that can be wrong. With the correct profile selected:
curl -v -X POST "$PREFECT_API_URL/orchestration/flows/count" \
-H "Authorization: Bearer $PREFECT_API_KEY" \
-H "Content-Type: application/json" \
-d '{}'
Try a couple of alternate endpoints (same base)
- Filter flows (POST)
curl -v -X POST "$PREFECT_API_URL/orchestration/flows/filter" \
-H "Authorization: Bearer $PREFECT_API_KEY" \
-H "Content-Type: application/json" \
-d '{}'
- Count deployments (POST)
curl -v -X POST "$PREFECT_API_URL/orchestration/deployments/count" \
-H "Authorization: Bearer $PREFECT_API_KEY" \
-H "Content-Type: application/json" \
-d '{}'
- Flow details (GET; use a known flow UUID)
curl -v \
-H "Authorization: Bearer $PREFECT_API_KEY" \
"$PREFECT_API_URL/orchestration/flows/<flow_uuid>"
If these still 404:
- Paste the exact PREFECT_API_URL
you copied from the UI (you can redact the UUIDs but leave the host; e.g., api vs api.eu).
- Confirm whether prefect flows ls
returns results with the same token/profile.
References
- Connect to Cloud (copy the correct API URL from the UI): Connect to Cloud
- REST: Count flows (POST + filters; in Cloud prepend your account/workspace base and /orchestration
): Count flows
I know, it’s thrilling. But one of those checks should flush out the mismatch.Owen Boyd
08/15/2025, 1:57 AMrm -rf ~/.prefect/
rm -rf .venv/
Then was able to re-login to cloud prefect
uvx prefect cloud login
Authed in the UI. Then I cleared out all local prefect envs and re-added only ones I was positive were correct. That still did not allow me to run a flow through uv run
, however, I could now at least ls flow runs through the cli
uvx prefect flow-run ls
I retried a curl with my API key that SHOULD allow me to do the equivalent with curl, but was still greeted with 404. (lost this command)
So I set up man in the middle proxy to intercept the request the CLI was sending (having trouble getting this from chrome devtools in browser):
uvx mitmproxy -p 8080
Yoinked the request (mitm calls them flows too) that the prefect cli was sending by running
HTTP_PROXY=<http://localhost:8080> HTTPS_PROXY=<http://localhost:8080> SSL_CERT_FILE=~/.mitmproxy/mitmproxy-ca-cert.pem uvx prefect flow-run ls
Which gave me the command:
curl -H 'Accept: */*' --compressed -H 'Connection: keep-alive' -H 'User-Agent: prefect/3.4.13 (API 0.8.4)' -H 'X-PREFECT-API-VERSION: 0.8.4' -H 'Authorization: Bearer KEY_FROM_CLI' -H 'Content-Type: application/json' -X POST <https://api.prefect.cloud/api/accounts/2836e4d2-a2d4-497c-942f-de64a280a687/workspaces/7ea575ae-d4d7-48a9-af73-3a831b94bf59/flows/filter> -d '{"flows":{"operator":"and_","id":{"any_":["033f3fd8-0930-4367-be10-88954600be6e","033f3fd8-0930-4367-be10-88954600be6e","033f3fd8-0930-4367-be10-88954600be6e","033f3fd8-0930-4367-be10-88954600be6e","033f3fd8-0930-4367-be10-88954600be6e","a14ffb37-c0df-4323-ad97-80adfb21d44d","a14ffb37-c0df-4323-ad97-80adfb21d44d","a14ffb37-c0df-4323-ad97-80adfb21d44d","a14ffb37-c0df-4323-ad97-80adfb21d44d","a14ffb37-c0df-4323-ad97-80adfb21d44d","a14ffb37-c0df-4323-ad97-80adfb21d44d","a14ffb37-c0df-4323-ad97-80adfb21d44d","a14ffb37-c0df-4323-ad97-80adfb21d44d","a14ffb37-c0df-4323-ad97-80adfb21d44d","a14ffb37-c0df-4323-ad97-80adfb21d44d"]},"name":null,"tags":null},"flow_runs":null,"task_runs":null,"deployments":null,"work_pools":null,"work_queues":null,"sort":null,"limit":null,"offset":0}'
This works! No 404 and the response is correct (tried with some other api endpoints too)
I then replaced KEY_FROM_CLI with my api key, and got the 404s again. Not informed enough to speculate on why that is, but I'm pretty sure I should be able to use my api key to list flows etc. Any ideas, thoughts on next steps, or people I should contact? It would be nice if this error mode had a more specific message...Marvin
08/15/2025, 1:57 AMMarvin
08/15/2025, 1:58 AMcurl -H 'Accept: */*' \
-H 'Connection: keep-alive' \
-H 'User-Agent: prefect/3.x (API 0.8.x)' \
-H 'X-PREFECT-API-VERSION: 0.8.4' \
-H 'Authorization: Bearer <new_workspace_key>' \
-H 'Content-Type: application/json' \
-X POST "<https://api.prefect.cloud/api/accounts/<account_uuid>/workspaces/<workspace_uuid>/flows/filter>" \
-d '{"flows":{},"limit":5}'
2) Verify the key/workspace alignment via CLI
- Use only your key in a clean profile:
prefect cloud logout
prefect cloud login --key "<your_api_key>"
prefect config view | grep PREFECT_API_URL
prefect flows ls
If flows ls
404s here, the key isn’t for that workspace.
3) Double-check region
- If your UI is app.eu.prefect.cloud
, the API must be api.eu.prefect.cloud
(the “Copy API URL” button in Settings > About is the source of truth).
Why 404 instead of 403?
- It’s deliberate to prevent enumeration across workspaces. I agree it’s not the most soothing DX. I’ll pass the feedback along; we can likely improve the error hinting when a token targets the wrong workspace.
Docs (for when you’re not packet-sniffing your own CLI)
- Connect to Cloud (copy the correct API URL and create keys in the right place): Connect to Cloud
- REST: Count flows (Cloud uses the same server endpoints; include the API version header as the CLI does): Count flows
If you generate a new key inside that workspace and the same curl still returns 404, send me:
- The host (api vs api.eu)
- The workspace/account UUIDs (safe to share)
- The response headers from curl -v
(redact the token)
And if you’d prefer direct help with account details, use the in-app Help chat in Prefect Cloud or email support@prefect.io with the workspace ID and timestamp of a failing request. We can check server-side logs for the token’s workspace binding.Owen Boyd
08/15/2025, 2:07 AM