/v1/organization/costs returning 404

Hi Team,

I am trying to call the Costs API as per the documentation:

https://platform.openai.com/docs/api-reference/usage/costs

GET https://api.openai.com/v1/organization/costs?start_time=1759257000&end_time=1761935400&bucket_width=1d&group_by=line_item,project_id
Headers:
Authorization: Bearer <api_key>
OpenAI-Organization: <org_id>

However, the request always returns:

Status: 404 Not Found
Body: (empty)

Other organization endpoints are working normally, so the key and permissions are valid.

please confirm whether this endpoint is currently enabled, or if there are additional requirements not mentioned in the documentation?

Thanks.

2 Likes

The API endpoint is most certainly missing or down. The Status 404 doesn’t even return a body error message.

httpx.HTTPStatusError: Client error '404 Not Found' for url 'https://api.openai.com/v1/organization/costs?start_time=1761350400'

Here’s a Python script distilled down, and where the function having “debug:True” sends only the required start date parameter (and I have API usage costs to return and tried 180 days, so 404 should not be ‘no results’).

'''OpenAI admin framework – costs endpoint example
Environment:
  export OPENAI_ADMIN_KEY=...            # required “sk‑admin‑…” key
  export OPENAI_ORG_ID=...               # optional
  export OPENAI_PROJECT_ID=...           # optional

Dependencies:
  pip install httpx
'''
from __future__ import annotations

import argparse
import json
import logging
import os
from datetime import UTC, datetime, timedelta
from typing import Any, Dict, Tuple

import httpx

logger = logging.getLogger(__name__)


# ---------------------------------------------------------------------------
#  Helpers
# ---------------------------------------------------------------------------

def get_auth_headers() -> Dict[str, str]:
    """Return standard admin headers plus JSON content negotiation."""
    api_key = os.getenv("OPENAI_ADMIN_KEY")
    if not api_key:
        raise ValueError("Set OPENAI_ADMIN_KEY first (must be an *admin* key).")

    headers: Dict[str, str] = {
        "Authorization": f"Bearer {api_key}",
        "Content-Type": "application/json", # debug: send this simply because OpenAI CURL has it
        "Accept": "application/json",
    }
    org_id = os.getenv("OPENAI_ORG_ID")
    project_id = os.getenv("OPENAI_PROJECT_ID")
    if org_id:
        headers["OpenAI-Organization"] = org_id
    if project_id:
        headers["OpenAI-Project"] = project_id  # unknown if useful (or breaking)
    return headers


def admin_get(
    path: str,
    *,
    params: Dict[str, Any] | None = None,
    timeout: float = 30.0,
) -> Tuple[httpx.Response, Dict[str, str]]:
    """GET wrapper for query-only OpenAI endpoints (no body/JSON)"""
    try:
        resp = httpx.get(
            f"https://api.openai.com{path}",
            headers=get_auth_headers(),
            params=params,
            timeout=timeout,
        )
        hdrs = dict(resp.headers)
        resp.raise_for_status()
        return resp, hdrs

    except httpx.HTTPStatusError as err:
        body_text = err.response.text.strip() or "<no body>"
        print(f"[Admin API] HTTP {err.response.status_code}: {body_text}", flush=True)
        logger.error("HTTP %s: %s", err.response.status_code, body_text)
        raise

    except httpx.RequestError as err:
        logger.error("Request error: %s", err)
        raise


# ---------------------------------------------------------------------------
#  Costs endpoint
# ---------------------------------------------------------------------------

def get_costs(
    past_days: int = 14,
    *,
    debug: bool = True,
) -> Dict[str, Any]:
    """
    Retrieve organisation‑level cost buckets.

    Parameters
    ----------
    past_days
        Number of 24‑hour buckets (1 – 180).
    debug
        • True  → send **only** the required `start_time`.  
        • False → include `end_time`, `limit`, `bucket_width`, & `group_by`.
    """
    past_days = max(1, min(past_days, 180))

    now = datetime.now(tz=UTC)
    start_dt = (now - timedelta(days=past_days)).replace(
        hour=0, minute=0, second=0, microsecond=0
    )

    params: Dict[str, Any] = {"start_time": int(start_dt.timestamp())}

    if not debug:
        params.update(
            {
                "end_time": int(now.timestamp()),
                "limit": past_days,
                "bucket_width": "1d",
                "group_by": ["line_item"],
            }
        )

    resp, _ = admin_get("/v1/organization/costs", params=params)
    return resp.json()


# ---------------------------------------------------------------------------
#  CLI
# ---------------------------------------------------------------------------

def main() -> None:
    parser = argparse.ArgumentParser("Fetch OpenAI organisation cost data")
    parser.add_argument("--days", type=int, default=14,
                        help="How many 24‑hour buckets (1‑180, default 14)")
    parser.add_argument("--full", action="store_true",
                        help="Send the full parameter set (turns off debug)")
    args = parser.parse_args()

    costs = get_costs(args.days, debug=not args.full)
    print(json.dumps(costs, indent=2, sort_keys=True))


if __name__ == "__main__":
    logging.basicConfig(level=logging.INFO)
    main()

Verified parameters against the API’s OpenAPI specification.

2 Likes

Thanks for reporting the issue, @Abhishek_N, and for confirming, @_j.

I was able to reproduce this on my end as well and have forwarded it to the OpenAI team.

5 Likes

Same issue. I use this api occasionally for updating daily costs in BI. Today suddenly it stopped working.

Can confirm, just wasted a few hours thinking it was my code after it was working fine yesterday. No content return is super weird.

Same bug, It’s critical… please fix it ASAP @OpenAI_Support @sps

It’s the same bug, 404 not found, and the response body is empty. please fix it ASAP @OpenAI_Support

Hello!

Thank you for reporting, we are currently investigating this issue. You can follow the updates on the incident raised on our Status Page.

2 Likes

Its working now, Thanks @Prashant_Pardesi

The issue is now resolved. The status page is updated as well. Thank you for reporting the issue.

2 Likes

This topic was automatically closed 2 days after the last reply. New replies are no longer allowed.