{
  "openapi": "3.1.0",
  "info": {
    "title": "Railway Public API",
    "version": "2.0.0",
    "description": "Railway's public API is GraphQL, served at a single endpoint. This document describes that endpoint and the OAuth 2.0 / OIDC endpoints used to authenticate to it. The GraphQL schema itself is available by introspection; see https://docs.railway.com/integrations/api and https://railway.com/auth.md.",
    "termsOfService": "https://railway.com/legal/terms",
    "contact": {
      "name": "Railway Support",
      "url": "https://station.railway.com",
      "email": "support@railway.com"
    }
  },
  "externalDocs": {
    "description": "Railway API documentation",
    "url": "https://docs.railway.com/integrations/api"
  },
  "servers": [
    {
      "url": "https://backboard.railway.com",
      "description": "Railway API (production)"
    }
  ],
  "security": [
    {
      "apiToken": []
    },
    {
      "oauth2": []
    }
  ],
  "paths": {
    "/graphql/v2": {
      "post": {
        "operationId": "executeGraphQL",
        "summary": "Execute a GraphQL query or mutation",
        "description": "The single entrypoint for Railway's public API. POST a GraphQL query or mutation; the schema is available by introspection against this same endpoint. Authorization failures return HTTP 200 with an `errors` array; validation failures return HTTP 400 with `extensions.code`. Every response carries a `traceId`.",
        "security": [
          {
            "apiToken": []
          },
          {
            "oauth2": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GraphQLRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "GraphQL execution result. `data` and/or `errors` per the GraphQL spec.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GraphQLResponse"
                }
              }
            }
          },
          "400": {
            "description": "Malformed request or GraphQL validation failure.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GraphQLResponse"
                }
              }
            }
          }
        }
      }
    },
    "/oauth/.well-known/openid-configuration": {
      "get": {
        "operationId": "getOpenIdConfiguration",
        "summary": "OpenID Connect discovery document",
        "description": "RFC 8414 authorization-server metadata: every OAuth endpoint, the JWKS URI, and the authoritative `scopes_supported` list.",
        "security": [],
        "responses": {
          "200": {
            "description": "OIDC discovery metadata.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/oauth/auth": {
      "get": {
        "operationId": "authorizeOAuth",
        "summary": "OAuth 2.0 authorization endpoint",
        "description": "Start the authorization-code flow (PKCE S256 required). Redirects the user to grant access to selected workspaces or projects.",
        "security": [],
        "parameters": [
          {
            "name": "client_id",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "redirect_uri",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uri"
            }
          },
          {
            "name": "response_type",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "code"
              ]
            }
          },
          {
            "name": "scope",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Space-delimited OAuth scopes."
          },
          {
            "name": "code_challenge",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "PKCE code challenge. Required for public clients — every CLI, editor, and MCP client — and used by agents."
          },
          {
            "name": "code_challenge_method",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "S256"
              ]
            },
            "description": "Must be S256 when code_challenge is present."
          },
          {
            "name": "state",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "302": {
            "description": "Redirect back to `redirect_uri` with an authorization `code`."
          }
        }
      }
    },
    "/oauth/token": {
      "post": {
        "operationId": "exchangeOAuthToken",
        "summary": "OAuth 2.0 token endpoint",
        "description": "Exchange an authorization code (or refresh token, or device code) for an access token. Access tokens expire after one hour; request `offline_access` with `prompt=consent` for a refresh token.",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "$ref": "#/components/schemas/TokenRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Token response.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TokenResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid grant or request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/oauth/register": {
      "post": {
        "operationId": "registerOAuthClient",
        "summary": "Dynamic client registration (RFC 7591)",
        "description": "Register an OAuth client dynamically. Used by MCP clients and other agents that don't have a pre-provisioned client id.",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ClientRegistrationRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The registered client.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/oauth/device/auth": {
      "post": {
        "operationId": "startDeviceAuthorization",
        "summary": "OAuth 2.0 device authorization endpoint (RFC 8628)",
        "description": "Start the device-code flow: returns a `device_code`, a `user_code`, and a `verification_uri` the user visits to approve. Poll `/oauth/token` with grant_type `urn:ietf:params:oauth:grant-type:device_code`. This is how the Railway CLI authenticates.",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "$ref": "#/components/schemas/DeviceAuthorizationRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Device authorization response.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DeviceAuthorizationResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/oauth/me": {
      "get": {
        "operationId": "getUserInfo",
        "summary": "OpenID Connect UserInfo endpoint",
        "description": "Return the claims (per the granted OIDC scopes) for the access token in the Authorization header.",
        "security": [
          {
            "oauth2": []
          }
        ],
        "responses": {
          "200": {
            "description": "UserInfo claims.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid access token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/oauth/request": {
      "post": {
        "operationId": "pushAuthorizationRequest",
        "summary": "Pushed Authorization Request endpoint (RFC 9126)",
        "description": "Push authorization parameters and receive a `request_uri` to use at `/oauth/auth`, keeping request parameters off the front channel. Optional; standard authorization via `/oauth/auth` also works.",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "additionalProperties": true
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "A `request_uri` and its expiry.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "apiToken": {
        "type": "http",
        "scheme": "bearer",
        "description": "A Railway API token (account, workspace, or project). Create one at https://railway.com/account/tokens. Send as `Authorization: Bearer <token>`."
      },
      "oauth2": {
        "type": "oauth2",
        "description": "Login with Railway (OAuth 2.0 + OIDC, PKCE S256). The authoritative scope list is `scopes_supported` in the OIDC discovery document.",
        "flows": {
          "authorizationCode": {
            "authorizationUrl": "https://backboard.railway.com/oauth/auth",
            "tokenUrl": "https://backboard.railway.com/oauth/token",
            "refreshUrl": "https://backboard.railway.com/oauth/token",
            "scopes": {
              "openid": "OpenID Connect sign-in",
              "email": "Read the user's email address",
              "profile": "Read the user's basic profile",
              "offline_access": "Receive a refresh token (request with prompt=consent)",
              "workspace:admin": "Full administrative access to selected workspaces",
              "workspace:member": "Read and write selected workspaces",
              "workspace:viewer": "Read-only access to selected workspaces",
              "project:admin": "Full administrative access to selected projects",
              "project:member": "Read and write selected projects",
              "project:viewer": "Read-only access to selected projects",
              "notifications": "Read and manage notifications",
              "ssh_keys": "Manage the user's SSH keys"
            }
          }
        }
      }
    },
    "schemas": {
      "GraphQLRequest": {
        "type": "object",
        "required": [
          "query"
        ],
        "properties": {
          "query": {
            "type": "string",
            "description": "The GraphQL query or mutation."
          },
          "variables": {
            "type": "object",
            "additionalProperties": true
          },
          "operationName": {
            "type": "string"
          }
        }
      },
      "GraphQLResponse": {
        "type": "object",
        "properties": {
          "data": {
            "type": [
              "object",
              "null"
            ],
            "additionalProperties": true
          },
          "errors": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/GraphQLError"
            }
          }
        }
      },
      "GraphQLError": {
        "type": "object",
        "required": [
          "message"
        ],
        "properties": {
          "message": {
            "type": "string"
          },
          "locations": {
            "type": "array",
            "items": {
              "type": "object"
            }
          },
          "path": {
            "type": "array",
            "items": {}
          },
          "extensions": {
            "type": "object",
            "properties": {
              "code": {
                "type": "string"
              },
              "traceId": {
                "type": "string"
              }
            },
            "additionalProperties": true
          }
        }
      },
      "TokenRequest": {
        "type": "object",
        "required": [
          "grant_type"
        ],
        "properties": {
          "grant_type": {
            "type": "string",
            "enum": [
              "authorization_code",
              "refresh_token",
              "urn:ietf:params:oauth:grant-type:device_code"
            ]
          },
          "code": {
            "type": "string"
          },
          "redirect_uri": {
            "type": "string",
            "format": "uri"
          },
          "client_id": {
            "type": "string"
          },
          "code_verifier": {
            "type": "string"
          },
          "refresh_token": {
            "type": "string"
          }
        }
      },
      "TokenResponse": {
        "type": "object",
        "properties": {
          "access_token": {
            "type": "string"
          },
          "token_type": {
            "type": "string"
          },
          "expires_in": {
            "type": "integer"
          },
          "refresh_token": {
            "type": "string"
          },
          "scope": {
            "type": "string"
          },
          "id_token": {
            "type": "string"
          }
        }
      },
      "ClientRegistrationRequest": {
        "type": "object",
        "properties": {
          "client_name": {
            "type": "string"
          },
          "redirect_uris": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "uri"
            }
          },
          "grant_types": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "token_endpoint_auth_method": {
            "type": "string"
          }
        }
      },
      "DeviceAuthorizationRequest": {
        "type": "object",
        "properties": {
          "client_id": {
            "type": "string"
          },
          "scope": {
            "type": "string",
            "description": "Space-delimited OAuth scopes."
          }
        }
      },
      "DeviceAuthorizationResponse": {
        "type": "object",
        "properties": {
          "device_code": {
            "type": "string"
          },
          "user_code": {
            "type": "string"
          },
          "verification_uri": {
            "type": "string",
            "format": "uri"
          },
          "verification_uri_complete": {
            "type": "string",
            "format": "uri"
          },
          "expires_in": {
            "type": "integer"
          },
          "interval": {
            "type": "integer"
          }
        }
      },
      "Error": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "string"
          },
          "error_description": {
            "type": "string"
          }
        }
      }
    }
  }
}