BetaHub API
BetaHub API
Home Docs 1.3

Projects

Returns a paginated list of projects visible to the current user. For authenticated users, returns projects they are a member of. For unauthenticated users or when all=true, returns publicly discoverable projects.
Authorization required

Authorization header for API access. Supports multiple authentication methods:

  1. Anonymous access: FormUser anonymous - for public operations
  2. Token-based access: FormUser tkn-{token} - for authenticated operations with legacy tokens
  3. Token with Email: FormUser tkn-{token},email:{email} - creates/links virtual user by email
  4. Token with Discord ID: FormUser tkn-{token},discord_id:{discord_id} - creates/links virtual user by Discord ID
  5. Token with JWT: FormUser tkn-{token},{jwt_token} - user identification with JWT token (legacy)
  6. Personal Access Tokens: Bearer YOUR_TOKEN_HERE - recommended for API integrations

Virtual User Creation

When using email: or discord_id: formats with FormUser tokens, the system automatically creates or reuses virtual users. Virtual users are accounts created on-the-fly for form submissions without requiring full user registration. This is useful for:

  • Linking form submissions to specific individuals by email or Discord ID
  • Tracking submissions across multiple reports from the same person
  • Creating user profiles without sign-up workflows

Virtual users created this way are marked as virtual accounts and work across Issues, Feature Requests, and Support Tickets.

Validation Rules:

  • email: format must match RFC 5322 email format. Invalid emails will fall back to anonymous access.
  • discord_id: format must be numeric (digits only). Invalid discord_ids will fall back to anonymous access.
  • Invalid identifiers do not cause HTTP errors; they fall back to anonymous authentication for graceful degradation.

Personal Access Tokens

Personal Access Tokens provide enhanced security and can be created and managed in your account settings. They are ideal for API integrations, automated scripts, and CI/CD pipelines. Tokens can have different permissions, including:

  • can_create_bug_report: Allows creating bug reports
  • can_create_feature_request: Allows creating feature requests
  • can_read_release_list: Allows listing releases
  • can_create_release: Allows creating new releases dynamically via release_label
  • can_update_issue: Allows updating existing issues
  • can_list_issues: Allows listing project issues For more information about Personal Access Tokens, see: https://betahub.io/docs/account/#personal-access-tokens
Query Parameters
Name Type Description
page optional integer Page number for pagination (default: 1)
all optional boolean When true, returns public/discoverable projects instead of the user’s member projects
cURL
curl \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  "https://app.betahub.io/projects.json?page=123&all=true"
Ruby
require "net/http"

uri = URI("https://app.betahub.io/projects.json?page=123&all=true")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Get.new(uri)
request["Authorization"] = "Bearer YOUR_API_TOKEN"

response = http.request(request)
puts response.body
Python
import requests

response = requests.get(
    "https://app.betahub.io/projects.json?page=123&all=true",
    headers={"Authorization": "Bearer YOUR_API_TOKEN"}
)
print(response.json())
JavaScript
const response = await fetch("https://app.betahub.io/projects.json?page=123&all=true", {
  headers: {
    "Authorization": "Bearer YOUR_API_TOKEN"
  }
});
const data = await response.json();
Java
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://app.betahub.io/projects.json?page=123&all=true"))
    .header("Authorization", "Bearer YOUR_API_TOKEN")
    .GET()
    .build();
HttpResponse<String> response = client.send(
    request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
Responses
application/json
{
  "projects": [
    {
      "id": "string",
      "name": "string",
      "description": "string",
      "created_at": "2026-03-12T10:30:00Z",
      "updated_at": "2026-03-12T10:30:00Z"
    }
  ],
  "pagination": {
    "current_page": 0,
    "total_pages": 0,
    "total_count": 0
  }
}
Returns detailed information about a specific project, including configuration, enabled modules, platforms, and the latest release.
Authorization required

Authorization header for API access. Supports multiple authentication methods:

  1. Anonymous access: FormUser anonymous - for public operations
  2. Token-based access: FormUser tkn-{token} - for authenticated operations with legacy tokens
  3. Token with Email: FormUser tkn-{token},email:{email} - creates/links virtual user by email
  4. Token with Discord ID: FormUser tkn-{token},discord_id:{discord_id} - creates/links virtual user by Discord ID
  5. Token with JWT: FormUser tkn-{token},{jwt_token} - user identification with JWT token (legacy)
  6. Personal Access Tokens: Bearer YOUR_TOKEN_HERE - recommended for API integrations

Virtual User Creation

When using email: or discord_id: formats with FormUser tokens, the system automatically creates or reuses virtual users. Virtual users are accounts created on-the-fly for form submissions without requiring full user registration. This is useful for:

  • Linking form submissions to specific individuals by email or Discord ID
  • Tracking submissions across multiple reports from the same person
  • Creating user profiles without sign-up workflows

Virtual users created this way are marked as virtual accounts and work across Issues, Feature Requests, and Support Tickets.

Validation Rules:

  • email: format must match RFC 5322 email format. Invalid emails will fall back to anonymous access.
  • discord_id: format must be numeric (digits only). Invalid discord_ids will fall back to anonymous access.
  • Invalid identifiers do not cause HTTP errors; they fall back to anonymous authentication for graceful degradation.

Personal Access Tokens

Personal Access Tokens provide enhanced security and can be created and managed in your account settings. They are ideal for API integrations, automated scripts, and CI/CD pipelines. Tokens can have different permissions, including:

  • can_create_bug_report: Allows creating bug reports
  • can_create_feature_request: Allows creating feature requests
  • can_read_release_list: Allows listing releases
  • can_create_release: Allows creating new releases dynamically via release_label
  • can_update_issue: Allows updating existing issues
  • can_list_issues: Allows listing project issues For more information about Personal Access Tokens, see: https://betahub.io/docs/account/#personal-access-tokens
Path Parameters
Name Type Description
id required string The project ID (obfuscated format, e.g. “pr-1234567”)
cURL
curl \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  "https://app.betahub.io/projects/123.json"
Ruby
require "net/http"

uri = URI("https://app.betahub.io/projects/123.json")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Get.new(uri)
request["Authorization"] = "Bearer YOUR_API_TOKEN"

response = http.request(request)
puts response.body
Python
import requests

response = requests.get(
    "https://app.betahub.io/projects/123.json",
    headers={"Authorization": "Bearer YOUR_API_TOKEN"}
)
print(response.json())
JavaScript
const response = await fetch("https://app.betahub.io/projects/123.json", {
  headers: {
    "Authorization": "Bearer YOUR_API_TOKEN"
  }
});
const data = await response.json();
Java
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://app.betahub.io/projects/123.json"))
    .header("Authorization", "Bearer YOUR_API_TOKEN")
    .GET()
    .build();
HttpResponse<String> response = client.send(
    request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
Responses
application/json
{
  "id": "string",
  "name": "string",
  "description": "string",
  "access": "string",
  "created_at": "2026-03-12T10:30:00Z",
  "updated_at": "2026-03-12T10:30:00Z",
  "url": "https://example.com",
  "sentiment_analysis": true,
  "support_knowledge": true,
  "support_knowledge_chunks_size": 0,
  "has_discord_bot": true,
  "modules": {},
  "platforms": [
    "string"
  ],
  "min_description_length": 0,
  "min_suggestion_length": 0,
  "latest_release": {
    "id": 0,
    "label": "string",
    "description": "string",
    "created_at": "2026-03-12T10:30:00Z",
    "updated_at": "2026-03-12T10:30:00Z",
    "url": "https://example.com"
  }
}
application/json
{
  "error": "string",
  "status": "string"
}
application/json
{
  "error": "string",
  "status": "string"
}

Issues

Retrieves a list of issues for the specified project. The response includes issue details such as ID, title, description, status, priority, and associated metadata.
Authorization required

Authorization header for API access. Supports multiple authentication methods:

  1. Anonymous access: FormUser anonymous - for public operations
  2. Token-based access: FormUser tkn-{token} - for authenticated operations with legacy tokens
  3. Token with Email: FormUser tkn-{token},email:{email} - creates/links virtual user by email
  4. Token with Discord ID: FormUser tkn-{token},discord_id:{discord_id} - creates/links virtual user by Discord ID
  5. Token with JWT: FormUser tkn-{token},{jwt_token} - user identification with JWT token (legacy)
  6. Personal Access Tokens: Bearer YOUR_TOKEN_HERE - recommended for API integrations

Virtual User Creation

When using email: or discord_id: formats with FormUser tokens, the system automatically creates or reuses virtual users. Virtual users are accounts created on-the-fly for form submissions without requiring full user registration. This is useful for:

  • Linking form submissions to specific individuals by email or Discord ID
  • Tracking submissions across multiple reports from the same person
  • Creating user profiles without sign-up workflows

Virtual users created this way are marked as virtual accounts and work across Issues, Feature Requests, and Support Tickets.

Validation Rules:

  • email: format must match RFC 5322 email format. Invalid emails will fall back to anonymous access.
  • discord_id: format must be numeric (digits only). Invalid discord_ids will fall back to anonymous access.
  • Invalid identifiers do not cause HTTP errors; they fall back to anonymous authentication for graceful degradation.

Personal Access Tokens

Personal Access Tokens provide enhanced security and can be created and managed in your account settings. They are ideal for API integrations, automated scripts, and CI/CD pipelines. Tokens can have different permissions, including:

  • can_create_bug_report: Allows creating bug reports
  • can_create_feature_request: Allows creating feature requests
  • can_read_release_list: Allows listing releases
  • can_create_release: Allows creating new releases dynamically via release_label
  • can_update_issue: Allows updating existing issues
  • can_list_issues: Allows listing project issues For more information about Personal Access Tokens, see: https://betahub.io/docs/account/#personal-access-tokens
Path Parameters
Name Type Description
project_id required string
Query Parameters
Name Type Description
page optional integer Page number for pagination (default: 1)
per_page optional integer Number of issues per page (default: 20, max: 100)
status optional string Filter issues by status
open in_progress resolved closed
priority optional string Filter issues by priority
low medium high critical
Header Parameters
Name Type Description
BetaHub-Project-ID required string BetaHub project ID, the same as the project_id
cURL
curl \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "BetaHub-Project-ID: 123" \
  "https://app.betahub.io/projects/123/issues.json?page=123&per_page=123&status=open&priority=low"
Ruby
require "net/http"

uri = URI("https://app.betahub.io/projects/123/issues.json?page=123&per_page=123&status=open&priority=low")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Get.new(uri)
request["Authorization"] = "Bearer YOUR_API_TOKEN"
request["BetaHub-Project-ID"] = "123"

response = http.request(request)
puts response.body
Python
import requests

response = requests.get(
    "https://app.betahub.io/projects/123/issues.json?page=123&per_page=123&status=open&priority=low",
    headers={"Authorization": "Bearer YOUR_API_TOKEN", "BetaHub-Project-ID": "123"}
)
print(response.json())
JavaScript
const response = await fetch("https://app.betahub.io/projects/123/issues.json?page=123&per_page=123&status=open&priority=low", {
  headers: {
    "Authorization": "Bearer YOUR_API_TOKEN",
    "BetaHub-Project-ID": "123"
  }
});
const data = await response.json();
Java
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://app.betahub.io/projects/123/issues.json?page=123&per_page=123&status=open&priority=low"))
    .header("Authorization", "Bearer YOUR_API_TOKEN")
    .header("BetaHub-Project-ID", "123")
    .GET()
    .build();
HttpResponse<String> response = client.send(
    request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
Responses
application/json
{
  "issues": [
    {
      "id": "1234abc",
      "title": "App crashes on login screen",
      "description": "When attempting to login, the app crashes after entering credentials.",
      "status": "open",
      "priority": "high",
      "created_at": "2024-10-03T12:34:56Z",
      "updated_at": "2024-10-03T12:34:56Z",
      "score": 95,
      "steps_to_reproduce": [
        {
          "step": "1. Open the app"
        },
        {
          "step": "2. Enter login credentials"
        },
        {
          "step": "3. Press login"
        }
      ],
      "assigned_to": {
        "id": "12",
        "name": "John Doe"
      },
      "reported_by": {
        "id": "34",
        "name": "Jane Smith"
      },
      "potential_duplicate": null,
      "url": "https://app.betahub.io/projects/1/issues/1234abc"
    }
  ],
  "pagination": {
    "current_page": 1,
    "per_page": 20,
    "total_pages": 5,
    "total_count": 95
  }
}

Creates a new issue for a project. Issues can be created in a draft mode, which allows for a step-by-step creation process.

Draft Mode Flow: 1. Create an issue with draft=true to keep it hidden (returns a JWT token in the ‘token’ field) 2. Optionally upload media files (screenshots, videos, log files) using the respective endpoints with the JWT token 3. Optionally set reporter email using the set_reporter_email endpoint 4. Publish the issue using the publish endpoint to make it visible

IMPORTANT NOTES:

  • Issue IDs in URLs must be prefixed with ‘g-‘ (e.g., /issues/g-12345 not /issues/12345) - JWT token is returned as ‘token’ (not ‘api_token’) and is only generated when using FormUser authentication
  • Use Bearer {jwt_token} for subsequent API calls after issue creation
  • Token is valid for 1 hour from issue creation
Authorization required

Authorization header for API access. Supports multiple authentication methods:

  1. Anonymous access: FormUser anonymous - for public operations
  2. Token-based access: FormUser tkn-{token} - for authenticated operations with legacy tokens
  3. Token with Email: FormUser tkn-{token},email:{email} - creates/links virtual user by email
  4. Token with Discord ID: FormUser tkn-{token},discord_id:{discord_id} - creates/links virtual user by Discord ID
  5. Token with JWT: FormUser tkn-{token},{jwt_token} - user identification with JWT token (legacy)
  6. Personal Access Tokens: Bearer YOUR_TOKEN_HERE - recommended for API integrations

Virtual User Creation

When using email: or discord_id: formats with FormUser tokens, the system automatically creates or reuses virtual users. Virtual users are accounts created on-the-fly for form submissions without requiring full user registration. This is useful for:

  • Linking form submissions to specific individuals by email or Discord ID
  • Tracking submissions across multiple reports from the same person
  • Creating user profiles without sign-up workflows

Virtual users created this way are marked as virtual accounts and work across Issues, Feature Requests, and Support Tickets.

Validation Rules:

  • email: format must match RFC 5322 email format. Invalid emails will fall back to anonymous access.
  • discord_id: format must be numeric (digits only). Invalid discord_ids will fall back to anonymous access.
  • Invalid identifiers do not cause HTTP errors; they fall back to anonymous authentication for graceful degradation.

Personal Access Tokens

Personal Access Tokens provide enhanced security and can be created and managed in your account settings. They are ideal for API integrations, automated scripts, and CI/CD pipelines. Tokens can have different permissions, including:

  • can_create_bug_report: Allows creating bug reports
  • can_create_feature_request: Allows creating feature requests
  • can_read_release_list: Allows listing releases
  • can_create_release: Allows creating new releases dynamically via release_label
  • can_update_issue: Allows updating existing issues
  • can_list_issues: Allows listing project issues For more information about Personal Access Tokens, see: https://betahub.io/docs/account/#personal-access-tokens
Path Parameters
Name Type Description
project_id required string
Header Parameters
Name Type Description
BetaHub-Project-ID required string BetaHub project ID, the same as the project_id
Request Body
application/x-www-form-urlencoded
  • issue[title] string optional Title of the issue. If not provided, a GenAI will be used to generate a title.
  • issue[description] string required Description of the issue.
  • issue[unformatted_steps_to_reproduce] string optional Steps to reproduce the issue. A GenAI will be used to format the steps into array.
  • issue[release_id] string optional ID of the release associated with this issue. If neither release_id nor release_label is provided, the latest release will be used.
  • issue[release_label] string optional Label for a release to associate with this issue. If the label exists, that release will be used; otherwise, a new release will be created (requires authorization token with create_release permission).
  • issue[source] string optional Optional source identifier for tracking where the issue was created from (e.g., “api”, “discord”, “dashboard”). Defaults to “dashboard” when created via web interface.
  • issue[custom][FIELD_IDENT] string optional

    Custom field values for the issue. Replace FIELD_IDENT with the field’s identifier (e.g., issue[custom][severity], issue[custom][platform]). Each project can define its own custom fields via the project settings. Field identifiers are snake_case strings (e.g., actual_result, player_cloud_id). You can find the available fields and their identifiers in the project’s Custom Fields settings page. Field types and expected values: - text: Any string value.

    • single_select: Must exactly match one of the allowed values (case-sensitive).
    • multi_select: An array of values, each matching one of the allowed values.
    • boolean: true, false, 1, or 0. Validation: If a custom field is marked as required in the project settings and is not provided (or blank), the API returns a 422 error indicating which field is missing. For single_select fields, the value must match one of the configured options exactly. JSON format: When using application/json, send custom fields as a nested object: {"issue": {"description": "...", "custom": {"severity": "Major", "platform": "Steam"}}}.
  • issue[debug_trace] object optional Optional structured debug information with severity-labeled steps. Maximum size 128KB. Expected format: {“steps”: [{“severity”: “info|warning|danger”, “description”: “text”}]}
  • draft boolean optional When set to true, the issue will be created in a hidden state for step-by-step completion. Default is false.
cURL
curl \
  -X POST \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "BetaHub-Project-ID: 123" \
  -d "issue[title]=Example title" \
  -d "issue[description]=Example description" \
  -d "issue[unformatted_steps_to_reproduce]=string" \
  -d "issue[release_id]=string" \
  -d "issue[release_label]=string" \
  -d "issue[source]=string" \
  "https://app.betahub.io/projects/123/issues.json"
Ruby
require "net/http"
require "json"

uri = URI("https://app.betahub.io/projects/123/issues.json")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Post.new(uri)
request["Authorization"] = "Bearer YOUR_API_TOKEN"
request["BetaHub-Project-ID"] = "123"
request.set_form_data({
  "issue[title]" => "Example title",
  "issue[description]" => "Example description",
  "issue[unformatted_steps_to_reproduce]" => "string",
  "issue[release_id]" => "string",
  "issue[release_label]" => "string",
  "issue[source]" => "string"
})

response = http.request(request)
puts response.body
Python
import requests

response = requests.post(
    "https://app.betahub.io/projects/123/issues.json",
    headers={"Authorization": "Bearer YOUR_API_TOKEN", "BetaHub-Project-ID": "123"},
    data={"issue[title]": "Example title", "issue[description]": "Example description", "issue[unformatted_steps_to_reproduce]": "string", "issue[release_id]": "string", "issue[release_label]": "string", "issue[source]": "string"}
)
print(response.json())
JavaScript
const response = await fetch("https://app.betahub.io/projects/123/issues.json", {
  method: "POST",
  headers: {
    "Authorization": "Bearer YOUR_API_TOKEN",
    "BetaHub-Project-ID": "123"
  }
});
const data = await response.json();
Java
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://app.betahub.io/projects/123/issues.json"))
    .header("Authorization", "Bearer YOUR_API_TOKEN")
    .header("BetaHub-Project-ID", "123")
    .header("Content-Type", "application/json")
    .POST(HttpRequest.BodyPublishers.ofString("{\"issue[title]\":\"string\",\"issue[description]\":\"string\",\"issue[unformatted_steps_to_reproduce]\":\"string\",\"issue[release_id]\":\"string\",\"issue[release_label]\":\"string\",\"issue[source]\":\"string\",\"issue[custom][FIELD_IDENT]\":\"string\",\"issue[debug_trace]\":{\"steps\":[{\"severity\":\"info\",\"description\":\"Process started successfully\"},{\"severity\":\"warning\",\"description\":\"Memory usage is high\"},{\"severity\":\"danger\",\"description\":\"Critical error occurred\"}]},\"draft\":true}"))
    .build();
HttpResponse<String> response = client.send(
    request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
Request Body
{
  "issue[title]": "string",
  "issue[description]": "string",
  "issue[unformatted_steps_to_reproduce]": "string",
  "issue[release_id]": "string",
  "issue[release_label]": "string",
  "issue[source]": "string",
  "issue[custom][FIELD_IDENT]": "string",
  "issue[debug_trace]": {
    "steps": [
      {
        "severity": "info",
        "description": "Process started successfully"
      },
      {
        "severity": "warning",
        "description": "Memory usage is high"
      },
      {
        "severity": "danger",
        "description": "Critical error occurred"
      }
    ]
  },
  "draft": true
}
Responses
application/json
{
  "issue[title]": "App crashes on login screen",
  "issue[description]": "When attempting to login, the app crashes after entering credentials.",
  "issue[unformatted_steps_to_reproduce]": "1. Open the app
2. Enter login credentials
3. Press login",
  "draft": true
}
application/json
{
  "error": "Auth token does not have permission to create releases",
  "status": "forbidden"
}
application/json
{
  "error": "Custom fields Severity is required, Custom fields Platform is required",
  "status": 422
}
Searches for issues (bug reports) within a project. Uses full-text search powered by Meilisearch to find matching issues based on the query string. Returns matching titles for autocomplete functionality or full issue objects for detailed results. Note: Search is performed across all issues in the project, then filtered by visibility permissions. The search includes issue titles and descriptions.
Authorization required

Authorization header for API access. Supports multiple authentication methods:

  1. Anonymous access: FormUser anonymous - for public operations
  2. Token-based access: FormUser tkn-{token} - for authenticated operations with legacy tokens
  3. Token with Email: FormUser tkn-{token},email:{email} - creates/links virtual user by email
  4. Token with Discord ID: FormUser tkn-{token},discord_id:{discord_id} - creates/links virtual user by Discord ID
  5. Token with JWT: FormUser tkn-{token},{jwt_token} - user identification with JWT token (legacy)
  6. Personal Access Tokens: Bearer YOUR_TOKEN_HERE - recommended for API integrations

Virtual User Creation

When using email: or discord_id: formats with FormUser tokens, the system automatically creates or reuses virtual users. Virtual users are accounts created on-the-fly for form submissions without requiring full user registration. This is useful for:

  • Linking form submissions to specific individuals by email or Discord ID
  • Tracking submissions across multiple reports from the same person
  • Creating user profiles without sign-up workflows

Virtual users created this way are marked as virtual accounts and work across Issues, Feature Requests, and Support Tickets.

Validation Rules:

  • email: format must match RFC 5322 email format. Invalid emails will fall back to anonymous access.
  • discord_id: format must be numeric (digits only). Invalid discord_ids will fall back to anonymous access.
  • Invalid identifiers do not cause HTTP errors; they fall back to anonymous authentication for graceful degradation.

Personal Access Tokens

Personal Access Tokens provide enhanced security and can be created and managed in your account settings. They are ideal for API integrations, automated scripts, and CI/CD pipelines. Tokens can have different permissions, including:

  • can_create_bug_report: Allows creating bug reports
  • can_create_feature_request: Allows creating feature requests
  • can_read_release_list: Allows listing releases
  • can_create_release: Allows creating new releases dynamically via release_label
  • can_update_issue: Allows updating existing issues
  • can_list_issues: Allows listing project issues For more information about Personal Access Tokens, see: https://betahub.io/docs/account/#personal-access-tokens
Path Parameters
Name Type Description
project_id required string
Query Parameters
Name Type Description
query required string The search query string to match against issue titles and descriptions
skip_ids optional string Comma-separated list of issue IDs to exclude from results
partial optional string When set to ‘true’, returns limited results optimized for autocomplete (max 4 results)
true false
scoped_id optional string Instead of searching, find a specific issue by its scoped ID (e.g., “123” or “g-456”)
Header Parameters
Name Type Description
BetaHub-Project-ID required string BetaHub project ID, the same as the project_id
cURL
curl \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "BetaHub-Project-ID: 123" \
  "https://app.betahub.io/projects/123/issues/search.json?query=example&skip_ids=123&partial=true&scoped_id=123"
Ruby
require "net/http"

uri = URI("https://app.betahub.io/projects/123/issues/search.json?query=example&skip_ids=123&partial=true&scoped_id=123")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Get.new(uri)
request["Authorization"] = "Bearer YOUR_API_TOKEN"
request["BetaHub-Project-ID"] = "123"

response = http.request(request)
puts response.body
Python
import requests

response = requests.get(
    "https://app.betahub.io/projects/123/issues/search.json?query=example&skip_ids=123&partial=true&scoped_id=123",
    headers={"Authorization": "Bearer YOUR_API_TOKEN", "BetaHub-Project-ID": "123"}
)
print(response.json())
JavaScript
const response = await fetch("https://app.betahub.io/projects/123/issues/search.json?query=example&skip_ids=123&partial=true&scoped_id=123", {
  headers: {
    "Authorization": "Bearer YOUR_API_TOKEN",
    "BetaHub-Project-ID": "123"
  }
});
const data = await response.json();
Java
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://app.betahub.io/projects/123/issues/search.json?query=example&skip_ids=123&partial=true&scoped_id=123"))
    .header("Authorization", "Bearer YOUR_API_TOKEN")
    .header("BetaHub-Project-ID", "123")
    .GET()
    .build();
HttpResponse<String> response = client.send(
    request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
Responses
application/json
{
  "issues": [
    {
      "id": "1234abc",
      "title": "App crashes on login screen",
      "status": "open",
      "priority": "high",
      "created_at": "2024-10-03T12:34:56Z"
    }
  ],
  "pagination": {
    "current_page": 1,
    "per_page": 25,
    "total_pages": 3,
    "total_count": 68
  },
  "project_id": 123
}
application/json
{
  "error": "string",
  "status": "string"
}
application/json
{
  "error": "string",
  "status": "string"
}
Alternative POST method for searching issues. Accepts the same parameters as the GET method but allows for longer search queries that might exceed URL length limits.
Authorization required

Authorization header for API access. Supports multiple authentication methods:

  1. Anonymous access: FormUser anonymous - for public operations
  2. Token-based access: FormUser tkn-{token} - for authenticated operations with legacy tokens
  3. Token with Email: FormUser tkn-{token},email:{email} - creates/links virtual user by email
  4. Token with Discord ID: FormUser tkn-{token},discord_id:{discord_id} - creates/links virtual user by Discord ID
  5. Token with JWT: FormUser tkn-{token},{jwt_token} - user identification with JWT token (legacy)
  6. Personal Access Tokens: Bearer YOUR_TOKEN_HERE - recommended for API integrations

Virtual User Creation

When using email: or discord_id: formats with FormUser tokens, the system automatically creates or reuses virtual users. Virtual users are accounts created on-the-fly for form submissions without requiring full user registration. This is useful for:

  • Linking form submissions to specific individuals by email or Discord ID
  • Tracking submissions across multiple reports from the same person
  • Creating user profiles without sign-up workflows

Virtual users created this way are marked as virtual accounts and work across Issues, Feature Requests, and Support Tickets.

Validation Rules:

  • email: format must match RFC 5322 email format. Invalid emails will fall back to anonymous access.
  • discord_id: format must be numeric (digits only). Invalid discord_ids will fall back to anonymous access.
  • Invalid identifiers do not cause HTTP errors; they fall back to anonymous authentication for graceful degradation.

Personal Access Tokens

Personal Access Tokens provide enhanced security and can be created and managed in your account settings. They are ideal for API integrations, automated scripts, and CI/CD pipelines. Tokens can have different permissions, including:

  • can_create_bug_report: Allows creating bug reports
  • can_create_feature_request: Allows creating feature requests
  • can_read_release_list: Allows listing releases
  • can_create_release: Allows creating new releases dynamically via release_label
  • can_update_issue: Allows updating existing issues
  • can_list_issues: Allows listing project issues For more information about Personal Access Tokens, see: https://betahub.io/docs/account/#personal-access-tokens
Path Parameters
Name Type Description
project_id required string
Header Parameters
Name Type Description
BetaHub-Project-ID required string BetaHub project ID, the same as the project_id
Request Body
application/x-www-form-urlencoded
  • query string required The search query string to match against issue titles and descriptions
  • skip_ids string optional Comma-separated list of issue IDs to exclude from results
  • partial string optional When set to ‘true’, returns limited results optimized for autocomplete (max 4 results)
    true false
  • scoped_id string optional Instead of searching, find a specific issue by its scoped ID
cURL
curl \
  -X POST \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "BetaHub-Project-ID: 123" \
  -d "query=string" \
  -d "skip_ids=string" \
  -d "partial=true" \
  -d "scoped_id=string" \
  "https://app.betahub.io/projects/123/issues/search.json"
Ruby
require "net/http"
require "json"

uri = URI("https://app.betahub.io/projects/123/issues/search.json")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Post.new(uri)
request["Authorization"] = "Bearer YOUR_API_TOKEN"
request["BetaHub-Project-ID"] = "123"
request.set_form_data({
  "query" => "string",
  "skip_ids" => "string",
  "partial" => "true",
  "scoped_id" => "string"
})

response = http.request(request)
puts response.body
Python
import requests

response = requests.post(
    "https://app.betahub.io/projects/123/issues/search.json",
    headers={"Authorization": "Bearer YOUR_API_TOKEN", "BetaHub-Project-ID": "123"},
    data={"query": "string", "skip_ids": "string", "partial": "true", "scoped_id": "string"}
)
print(response.json())
JavaScript
const response = await fetch("https://app.betahub.io/projects/123/issues/search.json", {
  method: "POST",
  headers: {
    "Authorization": "Bearer YOUR_API_TOKEN",
    "BetaHub-Project-ID": "123"
  }
});
const data = await response.json();
Java
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://app.betahub.io/projects/123/issues/search.json"))
    .header("Authorization", "Bearer YOUR_API_TOKEN")
    .header("BetaHub-Project-ID", "123")
    .header("Content-Type", "application/json")
    .POST(HttpRequest.BodyPublishers.ofString("{\"query\":\"string\",\"skip_ids\":\"string\",\"partial\":\"true\",\"scoped_id\":\"string\"}"))
    .build();
HttpResponse<String> response = client.send(
    request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
Request Body
{
  "query": "string",
  "skip_ids": "string",
  "partial": "true",
  "scoped_id": "string"
}
Responses
application/json
{}
application/json
{
  "error": "string",
  "status": "string"
}
application/json
{
  "error": "string",
  "status": "string"
}
Updates an existing issue with new information. Only certain fields can be updated, and the user must have appropriate permissions to modify the issue.
Authorization required

Authorization header for API access. Supports multiple authentication methods:

  1. Anonymous access: FormUser anonymous - for public operations
  2. Token-based access: FormUser tkn-{token} - for authenticated operations with legacy tokens
  3. Token with Email: FormUser tkn-{token},email:{email} - creates/links virtual user by email
  4. Token with Discord ID: FormUser tkn-{token},discord_id:{discord_id} - creates/links virtual user by Discord ID
  5. Token with JWT: FormUser tkn-{token},{jwt_token} - user identification with JWT token (legacy)
  6. Personal Access Tokens: Bearer YOUR_TOKEN_HERE - recommended for API integrations

Virtual User Creation

When using email: or discord_id: formats with FormUser tokens, the system automatically creates or reuses virtual users. Virtual users are accounts created on-the-fly for form submissions without requiring full user registration. This is useful for:

  • Linking form submissions to specific individuals by email or Discord ID
  • Tracking submissions across multiple reports from the same person
  • Creating user profiles without sign-up workflows

Virtual users created this way are marked as virtual accounts and work across Issues, Feature Requests, and Support Tickets.

Validation Rules:

  • email: format must match RFC 5322 email format. Invalid emails will fall back to anonymous access.
  • discord_id: format must be numeric (digits only). Invalid discord_ids will fall back to anonymous access.
  • Invalid identifiers do not cause HTTP errors; they fall back to anonymous authentication for graceful degradation.

Personal Access Tokens

Personal Access Tokens provide enhanced security and can be created and managed in your account settings. They are ideal for API integrations, automated scripts, and CI/CD pipelines. Tokens can have different permissions, including:

  • can_create_bug_report: Allows creating bug reports
  • can_create_feature_request: Allows creating feature requests
  • can_read_release_list: Allows listing releases
  • can_create_release: Allows creating new releases dynamically via release_label
  • can_update_issue: Allows updating existing issues
  • can_list_issues: Allows listing project issues For more information about Personal Access Tokens, see: https://betahub.io/docs/account/#personal-access-tokens
Path Parameters
Name Type Description
project_id required string
issue_id required string
Header Parameters
Name Type Description
BetaHub-Project-ID required string BetaHub project ID, the same as the project_id
Request Body
application/json
  • issue[title] string optional Updated title of the issue
  • issue[description] string optional Updated description of the issue
  • issue[status] string optional Updated status of the issue
    open in_progress resolved closed
  • issue[priority] string optional Updated priority of the issue
    low medium high critical
  • issue[assigned_to_id] string optional ID of the user to assign the issue to
  • issue[unformatted_steps_to_reproduce] string optional Updated steps to reproduce the issue
  • issue[release_id] string optional ID of the release to associate with the issue
cURL
curl \
  -X PUT \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "BetaHub-Project-ID: 123" \
  -H "Content-Type: application/json" \
  -d '{
  "issue[title]": "string",
  "issue[description]": "string",
  "issue[status]": "open",
  "issue[priority]": "low",
  "issue[assigned_to_id]": "string",
  "issue[unformatted_steps_to_reproduce]": "string",
  "issue[release_id]": "string"
}' \
  "https://app.betahub.io/projects/123/issues/g-123.json"
Ruby
require "net/http"
require "json"

uri = URI("https://app.betahub.io/projects/123/issues/g-123.json")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Put.new(uri)
request["Authorization"] = "Bearer YOUR_API_TOKEN"
request["BetaHub-Project-ID"] = "123"
request["Content-Type"] = "application/json"
request.body = {
  "issue[title]": "string",
  "issue[description]": "string",
  "issue[status]": "open",
  "issue[priority]": "low",
  "issue[assigned_to_id]": "string",
  "issue[unformatted_steps_to_reproduce]": "string",
  "issue[release_id]": "string"
}

response = http.request(request)
puts response.body
Python
import requests

response = requests.put(
    "https://app.betahub.io/projects/123/issues/g-123.json",
    headers={"Authorization": "Bearer YOUR_API_TOKEN", "BetaHub-Project-ID": "123"},
    json={
      "issue[title]": "string",
      "issue[description]": "string",
      "issue[status]": "open",
      "issue[priority]": "low",
      "issue[assigned_to_id]": "string",
      "issue[unformatted_steps_to_reproduce]": "string",
      "issue[release_id]": "string"
    }
)
print(response.json())
JavaScript
const response = await fetch("https://app.betahub.io/projects/123/issues/g-123.json", {
  method: "PUT",
  headers: {
    "Authorization": "Bearer YOUR_API_TOKEN",
    "BetaHub-Project-ID": "123",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    "issue[title]": "string",
    "issue[description]": "string",
    "issue[status]": "open",
    "issue[priority]": "low",
    "issue[assigned_to_id]": "string",
    "issue[unformatted_steps_to_reproduce]": "string",
    "issue[release_id]": "string"
  })
});
const data = await response.json();
Java
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://app.betahub.io/projects/123/issues/g-123.json"))
    .header("Authorization", "Bearer YOUR_API_TOKEN")
    .header("BetaHub-Project-ID", "123")
    .header("Content-Type", "application/json")
    .PUT(HttpRequest.BodyPublishers.ofString("{\"issue[title]\":\"string\",\"issue[description]\":\"string\",\"issue[status]\":\"open\",\"issue[priority]\":\"low\",\"issue[assigned_to_id]\":\"string\",\"issue[unformatted_steps_to_reproduce]\":\"string\",\"issue[release_id]\":\"string\"}"))
    .build();
HttpResponse<String> response = client.send(
    request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
Request Body
{
  "issue[title]": "string",
  "issue[description]": "string",
  "issue[status]": "open",
  "issue[priority]": "low",
  "issue[assigned_to_id]": "string",
  "issue[unformatted_steps_to_reproduce]": "string",
  "issue[release_id]": "string"
}
Responses
application/json
{
  "issue[title]": "Updated: App crashes on login screen",
  "issue[description]": "Updated description with more details about the crash.",
  "issue[status]": "in_progress",
  "issue[priority]": "critical"
}
application/json
{
  "error": "string",
  "status": "string"
}
application/json
{
  "error": "string",
  "status": "string"
}
application/json
{
  "error": "string",
  "status": "string"
}
DEPRECATED: Use set_contact_info instead. This endpoint is maintained for backward compatibility. Sets the reporter email for a draft issue. This creates a virtual user who will receive notifications about the issue. This endpoint now also supports discord_id parameter.
Authorization required

Authorization header for API access. Supports multiple authentication methods:

  1. Anonymous access: FormUser anonymous - for public operations
  2. Token-based access: FormUser tkn-{token} - for authenticated operations with legacy tokens
  3. Token with Email: FormUser tkn-{token},email:{email} - creates/links virtual user by email
  4. Token with Discord ID: FormUser tkn-{token},discord_id:{discord_id} - creates/links virtual user by Discord ID
  5. Token with JWT: FormUser tkn-{token},{jwt_token} - user identification with JWT token (legacy)
  6. Personal Access Tokens: Bearer YOUR_TOKEN_HERE - recommended for API integrations

Virtual User Creation

When using email: or discord_id: formats with FormUser tokens, the system automatically creates or reuses virtual users. Virtual users are accounts created on-the-fly for form submissions without requiring full user registration. This is useful for:

  • Linking form submissions to specific individuals by email or Discord ID
  • Tracking submissions across multiple reports from the same person
  • Creating user profiles without sign-up workflows

Virtual users created this way are marked as virtual accounts and work across Issues, Feature Requests, and Support Tickets.

Validation Rules:

  • email: format must match RFC 5322 email format. Invalid emails will fall back to anonymous access.
  • discord_id: format must be numeric (digits only). Invalid discord_ids will fall back to anonymous access.
  • Invalid identifiers do not cause HTTP errors; they fall back to anonymous authentication for graceful degradation.

Personal Access Tokens

Personal Access Tokens provide enhanced security and can be created and managed in your account settings. They are ideal for API integrations, automated scripts, and CI/CD pipelines. Tokens can have different permissions, including:

  • can_create_bug_report: Allows creating bug reports
  • can_create_feature_request: Allows creating feature requests
  • can_read_release_list: Allows listing releases
  • can_create_release: Allows creating new releases dynamically via release_label
  • can_update_issue: Allows updating existing issues
  • can_list_issues: Allows listing project issues For more information about Personal Access Tokens, see: https://betahub.io/docs/account/#personal-access-tokens
Path Parameters
Name Type Description
project_id required string
issue_id required string
Header Parameters
Name Type Description
BetaHub-Project-ID required string BetaHub project ID, the same as the project_id
Request Body
application/json
  • email string optional The email address of the reporter. Must be a valid email format.
  • discord_id string optional The Discord ID of the reporter. Must be numeric.
cURL
curl \
  -X POST \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "BetaHub-Project-ID: 123" \
  -H "Content-Type: application/json" \
  -d '{
  "email": "user@example.com",
  "discord_id": "string"
}' \
  "https://app.betahub.io/projects/123/issues/g-123/set_reporter_email"
Ruby
require "net/http"
require "json"

uri = URI("https://app.betahub.io/projects/123/issues/g-123/set_reporter_email")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Post.new(uri)
request["Authorization"] = "Bearer YOUR_API_TOKEN"
request["BetaHub-Project-ID"] = "123"
request["Content-Type"] = "application/json"
request.body = {
  "email": "user@example.com",
  "discord_id": "string"
}

response = http.request(request)
puts response.body
Python
import requests

response = requests.post(
    "https://app.betahub.io/projects/123/issues/g-123/set_reporter_email",
    headers={"Authorization": "Bearer YOUR_API_TOKEN", "BetaHub-Project-ID": "123"},
    json={
      "email": "user@example.com",
      "discord_id": "string"
    }
)
print(response.json())
JavaScript
const response = await fetch("https://app.betahub.io/projects/123/issues/g-123/set_reporter_email", {
  method: "POST",
  headers: {
    "Authorization": "Bearer YOUR_API_TOKEN",
    "BetaHub-Project-ID": "123",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    "email": "user@example.com",
    "discord_id": "string"
  })
});
const data = await response.json();
Java
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://app.betahub.io/projects/123/issues/g-123/set_reporter_email"))
    .header("Authorization", "Bearer YOUR_API_TOKEN")
    .header("BetaHub-Project-ID", "123")
    .header("Content-Type", "application/json")
    .POST(HttpRequest.BodyPublishers.ofString("{\"email\":\"user@example.com\",\"discord_id\":\"string\"}"))
    .build();
HttpResponse<String> response = client.send(
    request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
Request Body
{
  "email": "user@example.com",
  "discord_id": "string"
}
Responses
application/json
{
  "success": true,
  "message": "string",
  "issue_id": "string",
  "reporter": {
    "id": 0,
    "email": "string",
    "discord_id": "string",
    "virtual": true
  }
}
application/json
{
  "error": "string",
  "status": "string"
}
application/json
{
  "error": "string",
  "status": "string"
}
application/json
{
  "error": "string",
  "status": "string"
}
Sets contact information (email or Discord ID) for a draft issue reporter. This creates a virtual user who will receive notifications about the issue. This step is optional in the draft flow. Either email or discord_id must be provided.
Authorization required

Authorization header for API access. Supports multiple authentication methods:

  1. Anonymous access: FormUser anonymous - for public operations
  2. Token-based access: FormUser tkn-{token} - for authenticated operations with legacy tokens
  3. Token with Email: FormUser tkn-{token},email:{email} - creates/links virtual user by email
  4. Token with Discord ID: FormUser tkn-{token},discord_id:{discord_id} - creates/links virtual user by Discord ID
  5. Token with JWT: FormUser tkn-{token},{jwt_token} - user identification with JWT token (legacy)
  6. Personal Access Tokens: Bearer YOUR_TOKEN_HERE - recommended for API integrations

Virtual User Creation

When using email: or discord_id: formats with FormUser tokens, the system automatically creates or reuses virtual users. Virtual users are accounts created on-the-fly for form submissions without requiring full user registration. This is useful for:

  • Linking form submissions to specific individuals by email or Discord ID
  • Tracking submissions across multiple reports from the same person
  • Creating user profiles without sign-up workflows

Virtual users created this way are marked as virtual accounts and work across Issues, Feature Requests, and Support Tickets.

Validation Rules:

  • email: format must match RFC 5322 email format. Invalid emails will fall back to anonymous access.
  • discord_id: format must be numeric (digits only). Invalid discord_ids will fall back to anonymous access.
  • Invalid identifiers do not cause HTTP errors; they fall back to anonymous authentication for graceful degradation.

Personal Access Tokens

Personal Access Tokens provide enhanced security and can be created and managed in your account settings. They are ideal for API integrations, automated scripts, and CI/CD pipelines. Tokens can have different permissions, including:

  • can_create_bug_report: Allows creating bug reports
  • can_create_feature_request: Allows creating feature requests
  • can_read_release_list: Allows listing releases
  • can_create_release: Allows creating new releases dynamically via release_label
  • can_update_issue: Allows updating existing issues
  • can_list_issues: Allows listing project issues For more information about Personal Access Tokens, see: https://betahub.io/docs/account/#personal-access-tokens
Path Parameters
Name Type Description
project_id required string
issue_id required string
Header Parameters
Name Type Description
BetaHub-Project-ID required string BetaHub project ID, the same as the project_id
Request Body
application/json
  • email string optional The email address of the reporter. Must be a valid email format.
  • discord_id string optional The Discord ID of the reporter. Must be numeric.
cURL
curl \
  -X POST \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "BetaHub-Project-ID: 123" \
  -H "Content-Type: application/json" \
  -d '{
  "email": "user@example.com",
  "discord_id": "string"
}' \
  "https://app.betahub.io/projects/123/issues/g-123/set_contact_info"
Ruby
require "net/http"
require "json"

uri = URI("https://app.betahub.io/projects/123/issues/g-123/set_contact_info")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Post.new(uri)
request["Authorization"] = "Bearer YOUR_API_TOKEN"
request["BetaHub-Project-ID"] = "123"
request["Content-Type"] = "application/json"
request.body = {
  "email": "user@example.com",
  "discord_id": "string"
}

response = http.request(request)
puts response.body
Python
import requests

response = requests.post(
    "https://app.betahub.io/projects/123/issues/g-123/set_contact_info",
    headers={"Authorization": "Bearer YOUR_API_TOKEN", "BetaHub-Project-ID": "123"},
    json={
      "email": "user@example.com",
      "discord_id": "string"
    }
)
print(response.json())
JavaScript
const response = await fetch("https://app.betahub.io/projects/123/issues/g-123/set_contact_info", {
  method: "POST",
  headers: {
    "Authorization": "Bearer YOUR_API_TOKEN",
    "BetaHub-Project-ID": "123",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    "email": "user@example.com",
    "discord_id": "string"
  })
});
const data = await response.json();
Java
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://app.betahub.io/projects/123/issues/g-123/set_contact_info"))
    .header("Authorization", "Bearer YOUR_API_TOKEN")
    .header("BetaHub-Project-ID", "123")
    .header("Content-Type", "application/json")
    .POST(HttpRequest.BodyPublishers.ofString("{\"email\":\"user@example.com\",\"discord_id\":\"string\"}"))
    .build();
HttpResponse<String> response = client.send(
    request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
Request Body
{
  "email": "user@example.com",
  "discord_id": "string"
}
Responses
application/json
{
  "email": "reporter@example.com"
}
application/json
{
  "error": "Invalid email format"
}
application/json
{
  "error": "string",
  "status": "string"
}
application/json
{
  "error": "string",
  "status": "string"
}
Publishes a draft issue, changing its status from hidden to open and making it visible. This is the final step in the draft flow.
Authorization required

Authorization header for API access. Supports multiple authentication methods:

  1. Anonymous access: FormUser anonymous - for public operations
  2. Token-based access: FormUser tkn-{token} - for authenticated operations with legacy tokens
  3. Token with Email: FormUser tkn-{token},email:{email} - creates/links virtual user by email
  4. Token with Discord ID: FormUser tkn-{token},discord_id:{discord_id} - creates/links virtual user by Discord ID
  5. Token with JWT: FormUser tkn-{token},{jwt_token} - user identification with JWT token (legacy)
  6. Personal Access Tokens: Bearer YOUR_TOKEN_HERE - recommended for API integrations

Virtual User Creation

When using email: or discord_id: formats with FormUser tokens, the system automatically creates or reuses virtual users. Virtual users are accounts created on-the-fly for form submissions without requiring full user registration. This is useful for:

  • Linking form submissions to specific individuals by email or Discord ID
  • Tracking submissions across multiple reports from the same person
  • Creating user profiles without sign-up workflows

Virtual users created this way are marked as virtual accounts and work across Issues, Feature Requests, and Support Tickets.

Validation Rules:

  • email: format must match RFC 5322 email format. Invalid emails will fall back to anonymous access.
  • discord_id: format must be numeric (digits only). Invalid discord_ids will fall back to anonymous access.
  • Invalid identifiers do not cause HTTP errors; they fall back to anonymous authentication for graceful degradation.

Personal Access Tokens

Personal Access Tokens provide enhanced security and can be created and managed in your account settings. They are ideal for API integrations, automated scripts, and CI/CD pipelines. Tokens can have different permissions, including:

  • can_create_bug_report: Allows creating bug reports
  • can_create_feature_request: Allows creating feature requests
  • can_read_release_list: Allows listing releases
  • can_create_release: Allows creating new releases dynamically via release_label
  • can_update_issue: Allows updating existing issues
  • can_list_issues: Allows listing project issues For more information about Personal Access Tokens, see: https://betahub.io/docs/account/#personal-access-tokens
Path Parameters
Name Type Description
project_id required string
issue_id required string
Header Parameters
Name Type Description
BetaHub-Project-ID required string BetaHub project ID, the same as the project_id
Request Body
application/json
  • email_my_report boolean optional When set to true, an email will be sent to the reporter (if a valid email was set). Default is false.
cURL
curl \
  -X POST \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "BetaHub-Project-ID: 123" \
  -H "Content-Type: application/json" \
  -d '{
  "email_my_report": true
}' \
  "https://app.betahub.io/projects/123/issues/g-123/publish"
Ruby
require "net/http"
require "json"

uri = URI("https://app.betahub.io/projects/123/issues/g-123/publish")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Post.new(uri)
request["Authorization"] = "Bearer YOUR_API_TOKEN"
request["BetaHub-Project-ID"] = "123"
request["Content-Type"] = "application/json"
request.body = {
  "email_my_report": true
}

response = http.request(request)
puts response.body
Python
import requests

response = requests.post(
    "https://app.betahub.io/projects/123/issues/g-123/publish",
    headers={"Authorization": "Bearer YOUR_API_TOKEN", "BetaHub-Project-ID": "123"},
    json={
      "email_my_report": true
    }
)
print(response.json())
JavaScript
const response = await fetch("https://app.betahub.io/projects/123/issues/g-123/publish", {
  method: "POST",
  headers: {
    "Authorization": "Bearer YOUR_API_TOKEN",
    "BetaHub-Project-ID": "123",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    "email_my_report": true
  })
});
const data = await response.json();
Java
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://app.betahub.io/projects/123/issues/g-123/publish"))
    .header("Authorization", "Bearer YOUR_API_TOKEN")
    .header("BetaHub-Project-ID", "123")
    .header("Content-Type", "application/json")
    .POST(HttpRequest.BodyPublishers.ofString("{\"email_my_report\":true}"))
    .build();
HttpResponse<String> response = client.send(
    request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
Request Body
{
  "email_my_report": true
}
Responses
application/json
{
  "email_my_report": true
}
Sends a request to the issue reporter asking for additional information such as reproduction steps, screenshots, video clips, log files, or device information. This creates a notification for the reporter and adds the requester as a watcher.
Authorization required

Authorization header for API access. Supports multiple authentication methods:

  1. Anonymous access: FormUser anonymous - for public operations
  2. Token-based access: FormUser tkn-{token} - for authenticated operations with legacy tokens
  3. Token with Email: FormUser tkn-{token},email:{email} - creates/links virtual user by email
  4. Token with Discord ID: FormUser tkn-{token},discord_id:{discord_id} - creates/links virtual user by Discord ID
  5. Token with JWT: FormUser tkn-{token},{jwt_token} - user identification with JWT token (legacy)
  6. Personal Access Tokens: Bearer YOUR_TOKEN_HERE - recommended for API integrations

Virtual User Creation

When using email: or discord_id: formats with FormUser tokens, the system automatically creates or reuses virtual users. Virtual users are accounts created on-the-fly for form submissions without requiring full user registration. This is useful for:

  • Linking form submissions to specific individuals by email or Discord ID
  • Tracking submissions across multiple reports from the same person
  • Creating user profiles without sign-up workflows

Virtual users created this way are marked as virtual accounts and work across Issues, Feature Requests, and Support Tickets.

Validation Rules:

  • email: format must match RFC 5322 email format. Invalid emails will fall back to anonymous access.
  • discord_id: format must be numeric (digits only). Invalid discord_ids will fall back to anonymous access.
  • Invalid identifiers do not cause HTTP errors; they fall back to anonymous authentication for graceful degradation.

Personal Access Tokens

Personal Access Tokens provide enhanced security and can be created and managed in your account settings. They are ideal for API integrations, automated scripts, and CI/CD pipelines. Tokens can have different permissions, including:

  • can_create_bug_report: Allows creating bug reports
  • can_create_feature_request: Allows creating feature requests
  • can_read_release_list: Allows listing releases
  • can_create_release: Allows creating new releases dynamically via release_label
  • can_update_issue: Allows updating existing issues
  • can_list_issues: Allows listing project issues For more information about Personal Access Tokens, see: https://betahub.io/docs/account/#personal-access-tokens
Path Parameters
Name Type Description
project_id required string
issue_id required string
Header Parameters
Name Type Description
BetaHub-Project-ID required string BetaHub project ID, the same as the project_id
Request Body
application/json
  • what string required The type of additional information being requested from the reporter
    steps screenshot video logs device
  • comment string optional Optional comment or message to include with the request
cURL
curl \
  -X POST \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "BetaHub-Project-ID: 123" \
  -H "Content-Type: application/json" \
  -d '{
  "what": "steps",
  "comment": "string"
}' \
  "https://app.betahub.io/projects/123/issues/g-123/ask_for_details"
Ruby
require "net/http"
require "json"

uri = URI("https://app.betahub.io/projects/123/issues/g-123/ask_for_details")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Post.new(uri)
request["Authorization"] = "Bearer YOUR_API_TOKEN"
request["BetaHub-Project-ID"] = "123"
request["Content-Type"] = "application/json"
request.body = {
  "what": "steps",
  "comment": "string"
}

response = http.request(request)
puts response.body
Python
import requests

response = requests.post(
    "https://app.betahub.io/projects/123/issues/g-123/ask_for_details",
    headers={"Authorization": "Bearer YOUR_API_TOKEN", "BetaHub-Project-ID": "123"},
    json={
      "what": "steps",
      "comment": "string"
    }
)
print(response.json())
JavaScript
const response = await fetch("https://app.betahub.io/projects/123/issues/g-123/ask_for_details", {
  method: "POST",
  headers: {
    "Authorization": "Bearer YOUR_API_TOKEN",
    "BetaHub-Project-ID": "123",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    "what": "steps",
    "comment": "string"
  })
});
const data = await response.json();
Java
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://app.betahub.io/projects/123/issues/g-123/ask_for_details"))
    .header("Authorization", "Bearer YOUR_API_TOKEN")
    .header("BetaHub-Project-ID", "123")
    .header("Content-Type", "application/json")
    .POST(HttpRequest.BodyPublishers.ofString("{\"what\":\"steps\",\"comment\":\"string\"}"))
    .build();
HttpResponse<String> response = client.send(
    request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
Request Body
{
  "what": "steps",
  "comment": "string"
}
Responses
application/json
{
  "what": "steps",
  "comment": "Could you please provide detailed steps to reproduce this issue?"
}
application/json
{
  "error": "Invalid request type"
}
application/json
{
  "error": "string",
  "status": "string"
}
application/json
{
  "error": "string",
  "status": "string"
}

Screenshots

Returns all screenshots attached to the specified issue.
Authorization required

Authorization header for API access. Supports multiple authentication methods:

  1. Anonymous access: FormUser anonymous - for public operations
  2. Token-based access: FormUser tkn-{token} - for authenticated operations with legacy tokens
  3. Token with Email: FormUser tkn-{token},email:{email} - creates/links virtual user by email
  4. Token with Discord ID: FormUser tkn-{token},discord_id:{discord_id} - creates/links virtual user by Discord ID
  5. Token with JWT: FormUser tkn-{token},{jwt_token} - user identification with JWT token (legacy)
  6. Personal Access Tokens: Bearer YOUR_TOKEN_HERE - recommended for API integrations

Virtual User Creation

When using email: or discord_id: formats with FormUser tokens, the system automatically creates or reuses virtual users. Virtual users are accounts created on-the-fly for form submissions without requiring full user registration. This is useful for:

  • Linking form submissions to specific individuals by email or Discord ID
  • Tracking submissions across multiple reports from the same person
  • Creating user profiles without sign-up workflows

Virtual users created this way are marked as virtual accounts and work across Issues, Feature Requests, and Support Tickets.

Validation Rules:

  • email: format must match RFC 5322 email format. Invalid emails will fall back to anonymous access.
  • discord_id: format must be numeric (digits only). Invalid discord_ids will fall back to anonymous access.
  • Invalid identifiers do not cause HTTP errors; they fall back to anonymous authentication for graceful degradation.

Personal Access Tokens

Personal Access Tokens provide enhanced security and can be created and managed in your account settings. They are ideal for API integrations, automated scripts, and CI/CD pipelines. Tokens can have different permissions, including:

  • can_create_bug_report: Allows creating bug reports
  • can_create_feature_request: Allows creating feature requests
  • can_read_release_list: Allows listing releases
  • can_create_release: Allows creating new releases dynamically via release_label
  • can_update_issue: Allows updating existing issues
  • can_list_issues: Allows listing project issues For more information about Personal Access Tokens, see: https://betahub.io/docs/account/#personal-access-tokens
Path Parameters
Name Type Description
project_id required string
issue_id required string
Header Parameters
Name Type Description
BetaHub-Project-ID required string BetaHub project ID, the same as the project_id
cURL
curl \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "BetaHub-Project-ID: 123" \
  "https://app.betahub.io/projects/123/issues/g-123/screenshots"
Ruby
require "net/http"

uri = URI("https://app.betahub.io/projects/123/issues/g-123/screenshots")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Get.new(uri)
request["Authorization"] = "Bearer YOUR_API_TOKEN"
request["BetaHub-Project-ID"] = "123"

response = http.request(request)
puts response.body
Python
import requests

response = requests.get(
    "https://app.betahub.io/projects/123/issues/g-123/screenshots",
    headers={"Authorization": "Bearer YOUR_API_TOKEN", "BetaHub-Project-ID": "123"}
)
print(response.json())
JavaScript
const response = await fetch("https://app.betahub.io/projects/123/issues/g-123/screenshots", {
  headers: {
    "Authorization": "Bearer YOUR_API_TOKEN",
    "BetaHub-Project-ID": "123"
  }
});
const data = await response.json();
Java
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://app.betahub.io/projects/123/issues/g-123/screenshots"))
    .header("Authorization", "Bearer YOUR_API_TOKEN")
    .header("BetaHub-Project-ID", "123")
    .GET()
    .build();
HttpResponse<String> response = client.send(
    request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
Responses
application/json
[
  {
    "id": 0,
    "type": "screenshot",
    "description": "string",
    "size_bytes": 0,
    "media_size_bytes": 0,
    "content_type": "string",
    "url": "https://example.com",
    "filename": "string",
    "layer_a_url": "https://example.com",
    "layer_a_filename": "string",
    "created_at": "2026-03-12T10:30:00Z",
    "updated_at": "2026-03-12T10:30:00Z",
    "user": {
      "id": 0,
      "name": "string"
    }
  }
]
application/json
{
  "error": "string",
  "status": "string"
}
No description provided.
Authorization required

Authorization header for API access. Supports multiple authentication methods:

  1. Anonymous access: FormUser anonymous - for public operations
  2. Token-based access: FormUser tkn-{token} - for authenticated operations with legacy tokens
  3. Token with Email: FormUser tkn-{token},email:{email} - creates/links virtual user by email
  4. Token with Discord ID: FormUser tkn-{token},discord_id:{discord_id} - creates/links virtual user by Discord ID
  5. Token with JWT: FormUser tkn-{token},{jwt_token} - user identification with JWT token (legacy)
  6. Personal Access Tokens: Bearer YOUR_TOKEN_HERE - recommended for API integrations

Virtual User Creation

When using email: or discord_id: formats with FormUser tokens, the system automatically creates or reuses virtual users. Virtual users are accounts created on-the-fly for form submissions without requiring full user registration. This is useful for:

  • Linking form submissions to specific individuals by email or Discord ID
  • Tracking submissions across multiple reports from the same person
  • Creating user profiles without sign-up workflows

Virtual users created this way are marked as virtual accounts and work across Issues, Feature Requests, and Support Tickets.

Validation Rules:

  • email: format must match RFC 5322 email format. Invalid emails will fall back to anonymous access.
  • discord_id: format must be numeric (digits only). Invalid discord_ids will fall back to anonymous access.
  • Invalid identifiers do not cause HTTP errors; they fall back to anonymous authentication for graceful degradation.

Personal Access Tokens

Personal Access Tokens provide enhanced security and can be created and managed in your account settings. They are ideal for API integrations, automated scripts, and CI/CD pipelines. Tokens can have different permissions, including:

  • can_create_bug_report: Allows creating bug reports
  • can_create_feature_request: Allows creating feature requests
  • can_read_release_list: Allows listing releases
  • can_create_release: Allows creating new releases dynamically via release_label
  • can_update_issue: Allows updating existing issues
  • can_list_issues: Allows listing project issues For more information about Personal Access Tokens, see: https://betahub.io/docs/account/#personal-access-tokens
Path Parameters
Name Type Description
project_id required string
issue_id required string
Header Parameters
Name Type Description
BetaHub-Project-ID required string BetaHub project ID, the same as the project_id
Request Body
multipart/form-data
  • screenshot[image] string optional The screenshot image file
  • screenshot[name] string optional The name of the screenshot file. If set, the file will be saved with this name.
cURL
curl \
  -X POST \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "BetaHub-Project-ID: 123" \
  -F "screenshot[image]=@file.bin" \
  -F "screenshot[name]=string" \
  "https://app.betahub.io/projects/123/issues/g-123/screenshots"
Ruby
require "net/http"
require "json"

uri = URI("https://app.betahub.io/projects/123/issues/g-123/screenshots")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Post.new(uri)
request["Authorization"] = "Bearer YOUR_API_TOKEN"
request["BetaHub-Project-ID"] = "123"

response = http.request(request)
puts response.body
Python
import requests

response = requests.post(
    "https://app.betahub.io/projects/123/issues/g-123/screenshots",
    headers={"Authorization": "Bearer YOUR_API_TOKEN", "BetaHub-Project-ID": "123"}
)
print(response.json())
JavaScript
const response = await fetch("https://app.betahub.io/projects/123/issues/g-123/screenshots", {
  method: "POST",
  headers: {
    "Authorization": "Bearer YOUR_API_TOKEN",
    "BetaHub-Project-ID": "123"
  }
});
const data = await response.json();
Java
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://app.betahub.io/projects/123/issues/g-123/screenshots"))
    .header("Authorization", "Bearer YOUR_API_TOKEN")
    .header("BetaHub-Project-ID", "123")
    .header("Content-Type", "application/json")
    .POST(HttpRequest.BodyPublishers.ofString("{\"screenshot[image]\":\"string\",\"screenshot[name]\":\"string\"}"))
    .build();
HttpResponse<String> response = client.send(
    request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
Request Body
{
  "screenshot[image]": "string",
  "screenshot[name]": "string"
}
Responses
application/json
{
  "screenshot[image]": "(binary data representing an image)"
}
Request a presigned URL for uploading a screenshot directly to S3. This is the first step of the two-step direct upload process.
Authorization required
API token for accessing draft issues or performing direct uploads. Can be a JWT token returned from issue creation in draft mode, or other valid authorization tokens. Format: “Bearer TOKEN” or “FormUser tkn-TOKEN”
Path Parameters
Name Type Description
project_id required string
issue_id required string
Request Body
application/json
  • filename string required Name of the file to upload
  • byte_size integer required Size of the file in bytes
  • checksum string required Base64-encoded MD5 checksum of the file
  • content_type string required MIME type of the file
    image/png image/jpeg image/jpg
  • name string optional Optional display name for the screenshot file
cURL
curl \
  -X POST \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "filename": "screenshot.png",
  "byte_size": 1048576,
  "checksum": "1B2M2Y8AsgTpgAmY7PhCfg==",
  "content_type": "image/png",
  "name": "Player Death Screenshot"
}' \
  "https://app.betahub.io/projects/123/issues/g-123/screenshots/presigned_upload"
Ruby
require "net/http"
require "json"

uri = URI("https://app.betahub.io/projects/123/issues/g-123/screenshots/presigned_upload")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Post.new(uri)
request["Authorization"] = "Bearer YOUR_API_TOKEN"
request["Content-Type"] = "application/json"
request.body = {
  "filename": "screenshot.png",
  "byte_size": 1048576,
  "checksum": "1B2M2Y8AsgTpgAmY7PhCfg==",
  "content_type": "image/png",
  "name": "Player Death Screenshot"
}

response = http.request(request)
puts response.body
Python
import requests

response = requests.post(
    "https://app.betahub.io/projects/123/issues/g-123/screenshots/presigned_upload",
    headers={"Authorization": "Bearer YOUR_API_TOKEN"},
    json={
      "filename": "screenshot.png",
      "byte_size": 1048576,
      "checksum": "1B2M2Y8AsgTpgAmY7PhCfg==",
      "content_type": "image/png",
      "name": "Player Death Screenshot"
    }
)
print(response.json())
JavaScript
const response = await fetch("https://app.betahub.io/projects/123/issues/g-123/screenshots/presigned_upload", {
  method: "POST",
  headers: {
    "Authorization": "Bearer YOUR_API_TOKEN",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    "filename": "screenshot.png",
    "byte_size": 1048576,
    "checksum": "1B2M2Y8AsgTpgAmY7PhCfg==",
    "content_type": "image/png",
    "name": "Player Death Screenshot"
  })
});
const data = await response.json();
Java
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://app.betahub.io/projects/123/issues/g-123/screenshots/presigned_upload"))
    .header("Authorization", "Bearer YOUR_API_TOKEN")
    .header("Content-Type", "application/json")
    .POST(HttpRequest.BodyPublishers.ofString("{\"filename\":\"screenshot.png\",\"byte_size\":1048576,\"checksum\":\"1B2M2Y8AsgTpgAmY7PhCfg==\",\"content_type\":\"image/png\",\"name\":\"Player Death Screenshot\"}"))
    .build();
HttpResponse<String> response = client.send(
    request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
Request Body
{
  "filename": "screenshot.png",
  "byte_size": 1048576,
  "checksum": "1B2M2Y8AsgTpgAmY7PhCfg==",
  "content_type": "image/png",
  "name": "Player Death Screenshot"
}
Responses
application/json
{
  "blob_signed_id": "string",
  "direct_upload_url": "https://example.com",
  "headers": {},
  "blob_id": 0
}
application/json
{
  "errors": [
    "string"
  ],
  "message": "string"
}
application/json
{
  "error": "string",
  "status": "string"
}
Confirm that the file has been uploaded to S3 and attach it to the issue. This is the second step of the two-step direct upload process.
Authorization required
API token for accessing draft issues or performing direct uploads. Can be a JWT token returned from issue creation in draft mode, or other valid authorization tokens. Format: “Bearer TOKEN” or “FormUser tkn-TOKEN”
Path Parameters
Name Type Description
project_id required string
issue_id required string
Request Body
application/json
  • blob_signed_id string required Signed ID of the blob received from presigned_upload
  • name string optional Optional display name for the screenshot file
cURL
curl \
  -X POST \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "blob_signed_id": "string",
  "name": "Player Death Screenshot"
}' \
  "https://app.betahub.io/projects/123/issues/g-123/screenshots/confirm_upload"
Ruby
require "net/http"
require "json"

uri = URI("https://app.betahub.io/projects/123/issues/g-123/screenshots/confirm_upload")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Post.new(uri)
request["Authorization"] = "Bearer YOUR_API_TOKEN"
request["Content-Type"] = "application/json"
request.body = {
  "blob_signed_id": "string",
  "name": "Player Death Screenshot"
}

response = http.request(request)
puts response.body
Python
import requests

response = requests.post(
    "https://app.betahub.io/projects/123/issues/g-123/screenshots/confirm_upload",
    headers={"Authorization": "Bearer YOUR_API_TOKEN"},
    json={
      "blob_signed_id": "string",
      "name": "Player Death Screenshot"
    }
)
print(response.json())
JavaScript
const response = await fetch("https://app.betahub.io/projects/123/issues/g-123/screenshots/confirm_upload", {
  method: "POST",
  headers: {
    "Authorization": "Bearer YOUR_API_TOKEN",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    "blob_signed_id": "string",
    "name": "Player Death Screenshot"
  })
});
const data = await response.json();
Java
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://app.betahub.io/projects/123/issues/g-123/screenshots/confirm_upload"))
    .header("Authorization", "Bearer YOUR_API_TOKEN")
    .header("Content-Type", "application/json")
    .POST(HttpRequest.BodyPublishers.ofString("{\"blob_signed_id\":\"string\",\"name\":\"Player Death Screenshot\"}"))
    .build();
HttpResponse<String> response = client.send(
    request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
Request Body
{
  "blob_signed_id": "string",
  "name": "Player Death Screenshot"
}
Responses
application/json
{
  "id": "string",
  "created_at": "2026-03-12T10:30:00Z",
  "updated_at": "2026-03-12T10:30:00Z",
  "status": "string",
  "description": "string",
  "issue_id": "string",
  "image_url": "https://example.com"
}
application/json
{
  "errors": [
    "string"
  ],
  "message": "string"
}
application/json
{
  "error": "string",
  "status": "string"
}

Log Files

Returns all log files attached to the specified issue.
Authorization required

Authorization header for API access. Supports multiple authentication methods:

  1. Anonymous access: FormUser anonymous - for public operations
  2. Token-based access: FormUser tkn-{token} - for authenticated operations with legacy tokens
  3. Token with Email: FormUser tkn-{token},email:{email} - creates/links virtual user by email
  4. Token with Discord ID: FormUser tkn-{token},discord_id:{discord_id} - creates/links virtual user by Discord ID
  5. Token with JWT: FormUser tkn-{token},{jwt_token} - user identification with JWT token (legacy)
  6. Personal Access Tokens: Bearer YOUR_TOKEN_HERE - recommended for API integrations

Virtual User Creation

When using email: or discord_id: formats with FormUser tokens, the system automatically creates or reuses virtual users. Virtual users are accounts created on-the-fly for form submissions without requiring full user registration. This is useful for:

  • Linking form submissions to specific individuals by email or Discord ID
  • Tracking submissions across multiple reports from the same person
  • Creating user profiles without sign-up workflows

Virtual users created this way are marked as virtual accounts and work across Issues, Feature Requests, and Support Tickets.

Validation Rules:

  • email: format must match RFC 5322 email format. Invalid emails will fall back to anonymous access.
  • discord_id: format must be numeric (digits only). Invalid discord_ids will fall back to anonymous access.
  • Invalid identifiers do not cause HTTP errors; they fall back to anonymous authentication for graceful degradation.

Personal Access Tokens

Personal Access Tokens provide enhanced security and can be created and managed in your account settings. They are ideal for API integrations, automated scripts, and CI/CD pipelines. Tokens can have different permissions, including:

  • can_create_bug_report: Allows creating bug reports
  • can_create_feature_request: Allows creating feature requests
  • can_read_release_list: Allows listing releases
  • can_create_release: Allows creating new releases dynamically via release_label
  • can_update_issue: Allows updating existing issues
  • can_list_issues: Allows listing project issues For more information about Personal Access Tokens, see: https://betahub.io/docs/account/#personal-access-tokens
Path Parameters
Name Type Description
project_id required string
issue_id required string
Header Parameters
Name Type Description
BetaHub-Project-ID required string BetaHub project ID, the same as the project_id
cURL
curl \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "BetaHub-Project-ID: 123" \
  "https://app.betahub.io/projects/123/issues/g-123/log_files"
Ruby
require "net/http"

uri = URI("https://app.betahub.io/projects/123/issues/g-123/log_files")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Get.new(uri)
request["Authorization"] = "Bearer YOUR_API_TOKEN"
request["BetaHub-Project-ID"] = "123"

response = http.request(request)
puts response.body
Python
import requests

response = requests.get(
    "https://app.betahub.io/projects/123/issues/g-123/log_files",
    headers={"Authorization": "Bearer YOUR_API_TOKEN", "BetaHub-Project-ID": "123"}
)
print(response.json())
JavaScript
const response = await fetch("https://app.betahub.io/projects/123/issues/g-123/log_files", {
  headers: {
    "Authorization": "Bearer YOUR_API_TOKEN",
    "BetaHub-Project-ID": "123"
  }
});
const data = await response.json();
Java
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://app.betahub.io/projects/123/issues/g-123/log_files"))
    .header("Authorization", "Bearer YOUR_API_TOKEN")
    .header("BetaHub-Project-ID", "123")
    .GET()
    .build();
HttpResponse<String> response = client.send(
    request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
Responses
application/json
[
  {
    "id": 0,
    "created_at": "2026-03-12T10:30:00Z",
    "updated_at": "2026-03-12T10:30:00Z",
    "media_size_bytes": 0,
    "type": "log_file",
    "size_bytes": 0,
    "content_type": "text/plain",
    "url": "https://example.com",
    "filename": "string",
    "user": {
      "id": 0,
      "name": "string"
    }
  }
]
application/json
{
  "error": "string",
  "status": "string"
}

Upload a log file to an issue. Supports two methods:

Method 1: File upload — Send the file as multipart/form-data with log_file[file] field.

Method 2: Text content — Send log contents as a string via application/json, application/x-www-form-urlencoded, or multipart/form-data using the log_file[contents] field. The text will be stored as a .txt file. This is useful for clients that cannot perform file uploads (e.g., game engines with limited HTTP support).

Both methods support the optional log_file[name] field to set a custom filename.

Authorization required

Authorization header for API access. Supports multiple authentication methods:

  1. Anonymous access: FormUser anonymous - for public operations
  2. Token-based access: FormUser tkn-{token} - for authenticated operations with legacy tokens
  3. Token with Email: FormUser tkn-{token},email:{email} - creates/links virtual user by email
  4. Token with Discord ID: FormUser tkn-{token},discord_id:{discord_id} - creates/links virtual user by Discord ID
  5. Token with JWT: FormUser tkn-{token},{jwt_token} - user identification with JWT token (legacy)
  6. Personal Access Tokens: Bearer YOUR_TOKEN_HERE - recommended for API integrations

Virtual User Creation

When using email: or discord_id: formats with FormUser tokens, the system automatically creates or reuses virtual users. Virtual users are accounts created on-the-fly for form submissions without requiring full user registration. This is useful for:

  • Linking form submissions to specific individuals by email or Discord ID
  • Tracking submissions across multiple reports from the same person
  • Creating user profiles without sign-up workflows

Virtual users created this way are marked as virtual accounts and work across Issues, Feature Requests, and Support Tickets.

Validation Rules:

  • email: format must match RFC 5322 email format. Invalid emails will fall back to anonymous access.
  • discord_id: format must be numeric (digits only). Invalid discord_ids will fall back to anonymous access.
  • Invalid identifiers do not cause HTTP errors; they fall back to anonymous authentication for graceful degradation.

Personal Access Tokens

Personal Access Tokens provide enhanced security and can be created and managed in your account settings. They are ideal for API integrations, automated scripts, and CI/CD pipelines. Tokens can have different permissions, including:

  • can_create_bug_report: Allows creating bug reports
  • can_create_feature_request: Allows creating feature requests
  • can_read_release_list: Allows listing releases
  • can_create_release: Allows creating new releases dynamically via release_label
  • can_update_issue: Allows updating existing issues
  • can_list_issues: Allows listing project issues For more information about Personal Access Tokens, see: https://betahub.io/docs/account/#personal-access-tokens
Path Parameters
Name Type Description
project_id required string
issue_id required string
Header Parameters
Name Type Description
BetaHub-Project-ID required string BetaHub project ID, the same as the project_id
Request Body
multipart/form-data
  • log_file[file] string optional The log file binary data. Required unless log_file[contents] is provided.
  • log_file[contents] string optional Log contents as a plain string. Use this instead of log_file[file] when file uploads are not possible. The text will be stored as a text/plain file.
  • log_file[name] string optional Optional custom filename for the log file (e.g., “error_log.txt”).
cURL
curl \
  -X POST \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "BetaHub-Project-ID: 123" \
  -F "log_file[file]=@file.bin" \
  -F "log_file[contents]=@file.bin" \
  -F "log_file[name]=@file.bin" \
  "https://app.betahub.io/projects/123/issues/g-123/log_files"
Ruby
require "net/http"
require "json"

uri = URI("https://app.betahub.io/projects/123/issues/g-123/log_files")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Post.new(uri)
request["Authorization"] = "Bearer YOUR_API_TOKEN"
request["BetaHub-Project-ID"] = "123"

response = http.request(request)
puts response.body
Python
import requests

response = requests.post(
    "https://app.betahub.io/projects/123/issues/g-123/log_files",
    headers={"Authorization": "Bearer YOUR_API_TOKEN", "BetaHub-Project-ID": "123"}
)
print(response.json())
JavaScript
const response = await fetch("https://app.betahub.io/projects/123/issues/g-123/log_files", {
  method: "POST",
  headers: {
    "Authorization": "Bearer YOUR_API_TOKEN",
    "BetaHub-Project-ID": "123"
  }
});
const data = await response.json();
Java
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://app.betahub.io/projects/123/issues/g-123/log_files"))
    .header("Authorization", "Bearer YOUR_API_TOKEN")
    .header("BetaHub-Project-ID", "123")
    .header("Content-Type", "application/json")
    .POST(HttpRequest.BodyPublishers.ofString("{\"log_file[file]\":\"string\",\"log_file[contents]\":\"string\",\"log_file[name]\":\"string\"}"))
    .build();
HttpResponse<String> response = client.send(
    request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
Request Body
{
  "log_file[file]": "string",
  "log_file[contents]": "string",
  "log_file[name]": "string"
}
Responses
application/json
{
  "id": 0,
  "created_at": "2026-03-12T10:30:00Z",
  "updated_at": "2026-03-12T10:30:00Z",
  "media_size_bytes": 0,
  "type": "log_file",
  "size_bytes": 0,
  "content_type": "text/plain",
  "url": "https://example.com",
  "filename": "string",
  "user": {
    "id": 0,
    "name": "string"
  }
}
application/json
{
  "errors": [
    "string"
  ],
  "message": "string"
}
application/json
{
  "error": "string",
  "status": "string"
}
Request a presigned URL for uploading a log file directly to S3. This is the first step of the two-step direct upload process.
Authorization required
API token for accessing draft issues or performing direct uploads. Can be a JWT token returned from issue creation in draft mode, or other valid authorization tokens. Format: “Bearer TOKEN” or “FormUser tkn-TOKEN”
Path Parameters
Name Type Description
project_id required string
issue_id required string
Request Body
application/json
  • filename string required Name of the log file to upload
  • byte_size integer required Size of the file in bytes
  • checksum string required Base64-encoded MD5 checksum of the file
  • content_type string required MIME type of the log file
    text/plain text/log application/octet-stream text/x-log
  • name string optional Optional display name for the log file
cURL
curl \
  -X POST \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "filename": "application.log",
  "byte_size": 2048000,
  "checksum": "1B2M2Y8AsgTpgAmY7PhCfg==",
  "content_type": "text/plain",
  "name": "Debug Log"
}' \
  "https://app.betahub.io/projects/123/issues/g-123/log_files/presigned_upload"
Ruby
require "net/http"
require "json"

uri = URI("https://app.betahub.io/projects/123/issues/g-123/log_files/presigned_upload")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Post.new(uri)
request["Authorization"] = "Bearer YOUR_API_TOKEN"
request["Content-Type"] = "application/json"
request.body = {
  "filename": "application.log",
  "byte_size": 2048000,
  "checksum": "1B2M2Y8AsgTpgAmY7PhCfg==",
  "content_type": "text/plain",
  "name": "Debug Log"
}

response = http.request(request)
puts response.body
Python
import requests

response = requests.post(
    "https://app.betahub.io/projects/123/issues/g-123/log_files/presigned_upload",
    headers={"Authorization": "Bearer YOUR_API_TOKEN"},
    json={
      "filename": "application.log",
      "byte_size": 2048000,
      "checksum": "1B2M2Y8AsgTpgAmY7PhCfg==",
      "content_type": "text/plain",
      "name": "Debug Log"
    }
)
print(response.json())
JavaScript
const response = await fetch("https://app.betahub.io/projects/123/issues/g-123/log_files/presigned_upload", {
  method: "POST",
  headers: {
    "Authorization": "Bearer YOUR_API_TOKEN",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    "filename": "application.log",
    "byte_size": 2048000,
    "checksum": "1B2M2Y8AsgTpgAmY7PhCfg==",
    "content_type": "text/plain",
    "name": "Debug Log"
  })
});
const data = await response.json();
Java
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://app.betahub.io/projects/123/issues/g-123/log_files/presigned_upload"))
    .header("Authorization", "Bearer YOUR_API_TOKEN")
    .header("Content-Type", "application/json")
    .POST(HttpRequest.BodyPublishers.ofString("{\"filename\":\"application.log\",\"byte_size\":2048000,\"checksum\":\"1B2M2Y8AsgTpgAmY7PhCfg==\",\"content_type\":\"text/plain\",\"name\":\"Debug Log\"}"))
    .build();
HttpResponse<String> response = client.send(
    request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
Request Body
{
  "filename": "application.log",
  "byte_size": 2048000,
  "checksum": "1B2M2Y8AsgTpgAmY7PhCfg==",
  "content_type": "text/plain",
  "name": "Debug Log"
}
Responses
application/json
{
  "blob_signed_id": "string",
  "direct_upload_url": "https://example.com",
  "headers": {},
  "blob_id": 0
}
application/json
{
  "errors": [
    "string"
  ],
  "message": "string"
}
application/json
{
  "error": "string",
  "status": "string"
}
Confirm that the log file has been uploaded to S3 and attach it to the issue. This is the second step of the two-step direct upload process.
Authorization required
API token for accessing draft issues or performing direct uploads. Can be a JWT token returned from issue creation in draft mode, or other valid authorization tokens. Format: “Bearer TOKEN” or “FormUser tkn-TOKEN”
Path Parameters
Name Type Description
project_id required string
issue_id required string
Request Body
application/json
  • blob_signed_id string required Signed ID of the blob received from presigned_upload
  • name string optional Optional display name for the log file
cURL
curl \
  -X POST \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "blob_signed_id": "string",
  "name": "Debug Log"
}' \
  "https://app.betahub.io/projects/123/issues/g-123/log_files/confirm_upload"
Ruby
require "net/http"
require "json"

uri = URI("https://app.betahub.io/projects/123/issues/g-123/log_files/confirm_upload")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Post.new(uri)
request["Authorization"] = "Bearer YOUR_API_TOKEN"
request["Content-Type"] = "application/json"
request.body = {
  "blob_signed_id": "string",
  "name": "Debug Log"
}

response = http.request(request)
puts response.body
Python
import requests

response = requests.post(
    "https://app.betahub.io/projects/123/issues/g-123/log_files/confirm_upload",
    headers={"Authorization": "Bearer YOUR_API_TOKEN"},
    json={
      "blob_signed_id": "string",
      "name": "Debug Log"
    }
)
print(response.json())
JavaScript
const response = await fetch("https://app.betahub.io/projects/123/issues/g-123/log_files/confirm_upload", {
  method: "POST",
  headers: {
    "Authorization": "Bearer YOUR_API_TOKEN",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    "blob_signed_id": "string",
    "name": "Debug Log"
  })
});
const data = await response.json();
Java
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://app.betahub.io/projects/123/issues/g-123/log_files/confirm_upload"))
    .header("Authorization", "Bearer YOUR_API_TOKEN")
    .header("Content-Type", "application/json")
    .POST(HttpRequest.BodyPublishers.ofString("{\"blob_signed_id\":\"string\",\"name\":\"Debug Log\"}"))
    .build();
HttpResponse<String> response = client.send(
    request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
Request Body
{
  "blob_signed_id": "string",
  "name": "Debug Log"
}
Responses
application/json
{
  "id": 0,
  "created_at": "2026-03-12T10:30:00Z",
  "updated_at": "2026-03-12T10:30:00Z",
  "media_size_bytes": 0,
  "type": "log_file",
  "size_bytes": 0,
  "content_type": "text/plain",
  "url": "https://example.com",
  "filename": "string",
  "user": {
    "id": 0,
    "name": "string"
  }
}
application/json
{
  "errors": [
    "string"
  ],
  "message": "string"
}
application/json
{
  "error": "string",
  "status": "string"
}

Binary Files

Returns all binary files attached to the specified issue.
Authorization required

Authorization header for API access. Supports multiple authentication methods:

  1. Anonymous access: FormUser anonymous - for public operations
  2. Token-based access: FormUser tkn-{token} - for authenticated operations with legacy tokens
  3. Token with Email: FormUser tkn-{token},email:{email} - creates/links virtual user by email
  4. Token with Discord ID: FormUser tkn-{token},discord_id:{discord_id} - creates/links virtual user by Discord ID
  5. Token with JWT: FormUser tkn-{token},{jwt_token} - user identification with JWT token (legacy)
  6. Personal Access Tokens: Bearer YOUR_TOKEN_HERE - recommended for API integrations

Virtual User Creation

When using email: or discord_id: formats with FormUser tokens, the system automatically creates or reuses virtual users. Virtual users are accounts created on-the-fly for form submissions without requiring full user registration. This is useful for:

  • Linking form submissions to specific individuals by email or Discord ID
  • Tracking submissions across multiple reports from the same person
  • Creating user profiles without sign-up workflows

Virtual users created this way are marked as virtual accounts and work across Issues, Feature Requests, and Support Tickets.

Validation Rules:

  • email: format must match RFC 5322 email format. Invalid emails will fall back to anonymous access.
  • discord_id: format must be numeric (digits only). Invalid discord_ids will fall back to anonymous access.
  • Invalid identifiers do not cause HTTP errors; they fall back to anonymous authentication for graceful degradation.

Personal Access Tokens

Personal Access Tokens provide enhanced security and can be created and managed in your account settings. They are ideal for API integrations, automated scripts, and CI/CD pipelines. Tokens can have different permissions, including:

  • can_create_bug_report: Allows creating bug reports
  • can_create_feature_request: Allows creating feature requests
  • can_read_release_list: Allows listing releases
  • can_create_release: Allows creating new releases dynamically via release_label
  • can_update_issue: Allows updating existing issues
  • can_list_issues: Allows listing project issues For more information about Personal Access Tokens, see: https://betahub.io/docs/account/#personal-access-tokens
Path Parameters
Name Type Description
project_id required string
issue_id required string
Header Parameters
Name Type Description
BetaHub-Project-ID required string BetaHub project ID, the same as the project_id
cURL
curl \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "BetaHub-Project-ID: 123" \
  "https://app.betahub.io/projects/123/issues/g-123/binary_files"
Ruby
require "net/http"

uri = URI("https://app.betahub.io/projects/123/issues/g-123/binary_files")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Get.new(uri)
request["Authorization"] = "Bearer YOUR_API_TOKEN"
request["BetaHub-Project-ID"] = "123"

response = http.request(request)
puts response.body
Python
import requests

response = requests.get(
    "https://app.betahub.io/projects/123/issues/g-123/binary_files",
    headers={"Authorization": "Bearer YOUR_API_TOKEN", "BetaHub-Project-ID": "123"}
)
print(response.json())
JavaScript
const response = await fetch("https://app.betahub.io/projects/123/issues/g-123/binary_files", {
  headers: {
    "Authorization": "Bearer YOUR_API_TOKEN",
    "BetaHub-Project-ID": "123"
  }
});
const data = await response.json();
Java
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://app.betahub.io/projects/123/issues/g-123/binary_files"))
    .header("Authorization", "Bearer YOUR_API_TOKEN")
    .header("BetaHub-Project-ID", "123")
    .GET()
    .build();
HttpResponse<String> response = client.send(
    request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
Responses
application/json
[
  {
    "id": 0,
    "created_at": "2026-03-12T10:30:00Z",
    "updated_at": "2026-03-12T10:30:00Z",
    "media_size_bytes": 0,
    "type": "binary_file",
    "size_bytes": 0,
    "content_type": "application/octet-stream",
    "url": "https://example.com",
    "filename": "string",
    "user": {
      "id": 0,
      "name": "string"
    }
  }
]
application/json
{
  "error": "string",
  "status": "string"
}

Upload a binary file to an issue using multipart/form-data with binary_file[file] field.

The optional binary_file[name] field can be used to set a custom filename.

Authorization required

Authorization header for API access. Supports multiple authentication methods:

  1. Anonymous access: FormUser anonymous - for public operations
  2. Token-based access: FormUser tkn-{token} - for authenticated operations with legacy tokens
  3. Token with Email: FormUser tkn-{token},email:{email} - creates/links virtual user by email
  4. Token with Discord ID: FormUser tkn-{token},discord_id:{discord_id} - creates/links virtual user by Discord ID
  5. Token with JWT: FormUser tkn-{token},{jwt_token} - user identification with JWT token (legacy)
  6. Personal Access Tokens: Bearer YOUR_TOKEN_HERE - recommended for API integrations

Virtual User Creation

When using email: or discord_id: formats with FormUser tokens, the system automatically creates or reuses virtual users. Virtual users are accounts created on-the-fly for form submissions without requiring full user registration. This is useful for:

  • Linking form submissions to specific individuals by email or Discord ID
  • Tracking submissions across multiple reports from the same person
  • Creating user profiles without sign-up workflows

Virtual users created this way are marked as virtual accounts and work across Issues, Feature Requests, and Support Tickets.

Validation Rules:

  • email: format must match RFC 5322 email format. Invalid emails will fall back to anonymous access.
  • discord_id: format must be numeric (digits only). Invalid discord_ids will fall back to anonymous access.
  • Invalid identifiers do not cause HTTP errors; they fall back to anonymous authentication for graceful degradation.

Personal Access Tokens

Personal Access Tokens provide enhanced security and can be created and managed in your account settings. They are ideal for API integrations, automated scripts, and CI/CD pipelines. Tokens can have different permissions, including:

  • can_create_bug_report: Allows creating bug reports
  • can_create_feature_request: Allows creating feature requests
  • can_read_release_list: Allows listing releases
  • can_create_release: Allows creating new releases dynamically via release_label
  • can_update_issue: Allows updating existing issues
  • can_list_issues: Allows listing project issues For more information about Personal Access Tokens, see: https://betahub.io/docs/account/#personal-access-tokens
Path Parameters
Name Type Description
project_id required string
issue_id required string
Header Parameters
Name Type Description
BetaHub-Project-ID required string BetaHub project ID, the same as the project_id
Request Body
multipart/form-data
  • binary_file[file] string optional The binary file data.
  • binary_file[name] string optional Optional custom filename for the binary file.
cURL
curl \
  -X POST \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "BetaHub-Project-ID: 123" \
  -F "binary_file[file]=@file.bin" \
  -F "binary_file[name]=@file.bin" \
  "https://app.betahub.io/projects/123/issues/g-123/binary_files"
Ruby
require "net/http"
require "json"

uri = URI("https://app.betahub.io/projects/123/issues/g-123/binary_files")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Post.new(uri)
request["Authorization"] = "Bearer YOUR_API_TOKEN"
request["BetaHub-Project-ID"] = "123"

response = http.request(request)
puts response.body
Python
import requests

response = requests.post(
    "https://app.betahub.io/projects/123/issues/g-123/binary_files",
    headers={"Authorization": "Bearer YOUR_API_TOKEN", "BetaHub-Project-ID": "123"}
)
print(response.json())
JavaScript
const response = await fetch("https://app.betahub.io/projects/123/issues/g-123/binary_files", {
  method: "POST",
  headers: {
    "Authorization": "Bearer YOUR_API_TOKEN",
    "BetaHub-Project-ID": "123"
  }
});
const data = await response.json();
Java
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://app.betahub.io/projects/123/issues/g-123/binary_files"))
    .header("Authorization", "Bearer YOUR_API_TOKEN")
    .header("BetaHub-Project-ID", "123")
    .header("Content-Type", "application/json")
    .POST(HttpRequest.BodyPublishers.ofString("{\"binary_file[file]\":\"string\",\"binary_file[name]\":\"string\"}"))
    .build();
HttpResponse<String> response = client.send(
    request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
Request Body
{
  "binary_file[file]": "string",
  "binary_file[name]": "string"
}
Responses
application/json
{
  "id": 0,
  "created_at": "2026-03-12T10:30:00Z",
  "updated_at": "2026-03-12T10:30:00Z",
  "media_size_bytes": 0,
  "type": "binary_file",
  "size_bytes": 0,
  "content_type": "application/octet-stream",
  "url": "https://example.com",
  "filename": "string",
  "user": {
    "id": 0,
    "name": "string"
  }
}
application/json
{
  "errors": [
    "string"
  ],
  "message": "string"
}
application/json
{
  "error": "string",
  "status": "string"
}
Request a presigned URL for uploading a binary file directly to S3. This is the first step of the two-step direct upload process.
Authorization required
API token for accessing draft issues or performing direct uploads. Can be a JWT token returned from issue creation in draft mode, or other valid authorization tokens. Format: “Bearer TOKEN” or “FormUser tkn-TOKEN”
Path Parameters
Name Type Description
project_id required string
issue_id required string
Request Body
application/json
  • filename string required Name of the binary file to upload
  • byte_size integer required Size of the file in bytes
  • checksum string required Base64-encoded MD5 checksum of the file
  • content_type string required MIME type of the binary file
  • name string optional Optional display name for the binary file
cURL
curl \
  -X POST \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "filename": "crashdump.bin",
  "byte_size": 2048000,
  "checksum": "1B2M2Y8AsgTpgAmY7PhCfg==",
  "content_type": "application/octet-stream",
  "name": "Crash Dump"
}' \
  "https://app.betahub.io/projects/123/issues/g-123/binary_files/presigned_upload"
Ruby
require "net/http"
require "json"

uri = URI("https://app.betahub.io/projects/123/issues/g-123/binary_files/presigned_upload")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Post.new(uri)
request["Authorization"] = "Bearer YOUR_API_TOKEN"
request["Content-Type"] = "application/json"
request.body = {
  "filename": "crashdump.bin",
  "byte_size": 2048000,
  "checksum": "1B2M2Y8AsgTpgAmY7PhCfg==",
  "content_type": "application/octet-stream",
  "name": "Crash Dump"
}

response = http.request(request)
puts response.body
Python
import requests

response = requests.post(
    "https://app.betahub.io/projects/123/issues/g-123/binary_files/presigned_upload",
    headers={"Authorization": "Bearer YOUR_API_TOKEN"},
    json={
      "filename": "crashdump.bin",
      "byte_size": 2048000,
      "checksum": "1B2M2Y8AsgTpgAmY7PhCfg==",
      "content_type": "application/octet-stream",
      "name": "Crash Dump"
    }
)
print(response.json())
JavaScript
const response = await fetch("https://app.betahub.io/projects/123/issues/g-123/binary_files/presigned_upload", {
  method: "POST",
  headers: {
    "Authorization": "Bearer YOUR_API_TOKEN",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    "filename": "crashdump.bin",
    "byte_size": 2048000,
    "checksum": "1B2M2Y8AsgTpgAmY7PhCfg==",
    "content_type": "application/octet-stream",
    "name": "Crash Dump"
  })
});
const data = await response.json();
Java
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://app.betahub.io/projects/123/issues/g-123/binary_files/presigned_upload"))
    .header("Authorization", "Bearer YOUR_API_TOKEN")
    .header("Content-Type", "application/json")
    .POST(HttpRequest.BodyPublishers.ofString("{\"filename\":\"crashdump.bin\",\"byte_size\":2048000,\"checksum\":\"1B2M2Y8AsgTpgAmY7PhCfg==\",\"content_type\":\"application/octet-stream\",\"name\":\"Crash Dump\"}"))
    .build();
HttpResponse<String> response = client.send(
    request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
Request Body
{
  "filename": "crashdump.bin",
  "byte_size": 2048000,
  "checksum": "1B2M2Y8AsgTpgAmY7PhCfg==",
  "content_type": "application/octet-stream",
  "name": "Crash Dump"
}
Responses
application/json
{
  "blob_signed_id": "string",
  "direct_upload_url": "https://example.com",
  "headers": {},
  "blob_id": 0
}
application/json
{
  "errors": [
    "string"
  ],
  "message": "string"
}
application/json
{
  "error": "string",
  "status": "string"
}
Confirm that the binary file has been uploaded to S3 and attach it to the issue. This is the second step of the two-step direct upload process.
Authorization required
API token for accessing draft issues or performing direct uploads. Can be a JWT token returned from issue creation in draft mode, or other valid authorization tokens. Format: “Bearer TOKEN” or “FormUser tkn-TOKEN”
Path Parameters
Name Type Description
project_id required string
issue_id required string
Request Body
application/json
  • blob_signed_id string required Signed ID of the blob received from presigned_upload
  • name string optional Optional display name for the binary file
cURL
curl \
  -X POST \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "blob_signed_id": "string",
  "name": "Crash Dump"
}' \
  "https://app.betahub.io/projects/123/issues/g-123/binary_files/confirm_upload"
Ruby
require "net/http"
require "json"

uri = URI("https://app.betahub.io/projects/123/issues/g-123/binary_files/confirm_upload")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Post.new(uri)
request["Authorization"] = "Bearer YOUR_API_TOKEN"
request["Content-Type"] = "application/json"
request.body = {
  "blob_signed_id": "string",
  "name": "Crash Dump"
}

response = http.request(request)
puts response.body
Python
import requests

response = requests.post(
    "https://app.betahub.io/projects/123/issues/g-123/binary_files/confirm_upload",
    headers={"Authorization": "Bearer YOUR_API_TOKEN"},
    json={
      "blob_signed_id": "string",
      "name": "Crash Dump"
    }
)
print(response.json())
JavaScript
const response = await fetch("https://app.betahub.io/projects/123/issues/g-123/binary_files/confirm_upload", {
  method: "POST",
  headers: {
    "Authorization": "Bearer YOUR_API_TOKEN",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    "blob_signed_id": "string",
    "name": "Crash Dump"
  })
});
const data = await response.json();
Java
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://app.betahub.io/projects/123/issues/g-123/binary_files/confirm_upload"))
    .header("Authorization", "Bearer YOUR_API_TOKEN")
    .header("Content-Type", "application/json")
    .POST(HttpRequest.BodyPublishers.ofString("{\"blob_signed_id\":\"string\",\"name\":\"Crash Dump\"}"))
    .build();
HttpResponse<String> response = client.send(
    request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
Request Body
{
  "blob_signed_id": "string",
  "name": "Crash Dump"
}
Responses
application/json
{
  "id": 0,
  "created_at": "2026-03-12T10:30:00Z",
  "updated_at": "2026-03-12T10:30:00Z",
  "media_size_bytes": 0,
  "type": "binary_file",
  "size_bytes": 0,
  "content_type": "application/octet-stream",
  "url": "https://example.com",
  "filename": "string",
  "user": {
    "id": 0,
    "name": "string"
  }
}
application/json
{
  "errors": [
    "string"
  ],
  "message": "string"
}
application/json
{
  "error": "string",
  "status": "string"
}

Video Clips

Returns all video clips attached to the specified issue.
Authorization required

Authorization header for API access. Supports multiple authentication methods:

  1. Anonymous access: FormUser anonymous - for public operations
  2. Token-based access: FormUser tkn-{token} - for authenticated operations with legacy tokens
  3. Token with Email: FormUser tkn-{token},email:{email} - creates/links virtual user by email
  4. Token with Discord ID: FormUser tkn-{token},discord_id:{discord_id} - creates/links virtual user by Discord ID
  5. Token with JWT: FormUser tkn-{token},{jwt_token} - user identification with JWT token (legacy)
  6. Personal Access Tokens: Bearer YOUR_TOKEN_HERE - recommended for API integrations

Virtual User Creation

When using email: or discord_id: formats with FormUser tokens, the system automatically creates or reuses virtual users. Virtual users are accounts created on-the-fly for form submissions without requiring full user registration. This is useful for:

  • Linking form submissions to specific individuals by email or Discord ID
  • Tracking submissions across multiple reports from the same person
  • Creating user profiles without sign-up workflows

Virtual users created this way are marked as virtual accounts and work across Issues, Feature Requests, and Support Tickets.

Validation Rules:

  • email: format must match RFC 5322 email format. Invalid emails will fall back to anonymous access.
  • discord_id: format must be numeric (digits only). Invalid discord_ids will fall back to anonymous access.
  • Invalid identifiers do not cause HTTP errors; they fall back to anonymous authentication for graceful degradation.

Personal Access Tokens

Personal Access Tokens provide enhanced security and can be created and managed in your account settings. They are ideal for API integrations, automated scripts, and CI/CD pipelines. Tokens can have different permissions, including:

  • can_create_bug_report: Allows creating bug reports
  • can_create_feature_request: Allows creating feature requests
  • can_read_release_list: Allows listing releases
  • can_create_release: Allows creating new releases dynamically via release_label
  • can_update_issue: Allows updating existing issues
  • can_list_issues: Allows listing project issues For more information about Personal Access Tokens, see: https://betahub.io/docs/account/#personal-access-tokens
Path Parameters
Name Type Description
project_id required string
issue_id required string
Header Parameters
Name Type Description
BetaHub-Project-ID required string BetaHub project ID, the same as the project_id
cURL
curl \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "BetaHub-Project-ID: 123" \
  "https://app.betahub.io/projects/123/issues/g-123/video_clips"
Ruby
require "net/http"

uri = URI("https://app.betahub.io/projects/123/issues/g-123/video_clips")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Get.new(uri)
request["Authorization"] = "Bearer YOUR_API_TOKEN"
request["BetaHub-Project-ID"] = "123"

response = http.request(request)
puts response.body
Python
import requests

response = requests.get(
    "https://app.betahub.io/projects/123/issues/g-123/video_clips",
    headers={"Authorization": "Bearer YOUR_API_TOKEN", "BetaHub-Project-ID": "123"}
)
print(response.json())
JavaScript
const response = await fetch("https://app.betahub.io/projects/123/issues/g-123/video_clips", {
  headers: {
    "Authorization": "Bearer YOUR_API_TOKEN",
    "BetaHub-Project-ID": "123"
  }
});
const data = await response.json();
Java
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://app.betahub.io/projects/123/issues/g-123/video_clips"))
    .header("Authorization", "Bearer YOUR_API_TOKEN")
    .header("BetaHub-Project-ID", "123")
    .GET()
    .build();
HttpResponse<String> response = client.send(
    request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
Responses
application/json
[
  {
    "id": 0,
    "type": "video_clip",
    "processing": true,
    "processed": true,
    "failed": true,
    "size_bytes": 0,
    "media_size_bytes": 0,
    "content_type": "string",
    "url": "https://example.com",
    "filename": "string",
    "created_at": "2026-03-12T10:30:00Z",
    "updated_at": "2026-03-12T10:30:00Z",
    "user": {
      "id": 0,
      "name": "string"
    }
  }
]
application/json
{
  "error": "string",
  "status": "string"
}
No description provided.
Authorization required

Authorization header for API access. Supports multiple authentication methods:

  1. Anonymous access: FormUser anonymous - for public operations
  2. Token-based access: FormUser tkn-{token} - for authenticated operations with legacy tokens
  3. Token with Email: FormUser tkn-{token},email:{email} - creates/links virtual user by email
  4. Token with Discord ID: FormUser tkn-{token},discord_id:{discord_id} - creates/links virtual user by Discord ID
  5. Token with JWT: FormUser tkn-{token},{jwt_token} - user identification with JWT token (legacy)
  6. Personal Access Tokens: Bearer YOUR_TOKEN_HERE - recommended for API integrations

Virtual User Creation

When using email: or discord_id: formats with FormUser tokens, the system automatically creates or reuses virtual users. Virtual users are accounts created on-the-fly for form submissions without requiring full user registration. This is useful for:

  • Linking form submissions to specific individuals by email or Discord ID
  • Tracking submissions across multiple reports from the same person
  • Creating user profiles without sign-up workflows

Virtual users created this way are marked as virtual accounts and work across Issues, Feature Requests, and Support Tickets.

Validation Rules:

  • email: format must match RFC 5322 email format. Invalid emails will fall back to anonymous access.
  • discord_id: format must be numeric (digits only). Invalid discord_ids will fall back to anonymous access.
  • Invalid identifiers do not cause HTTP errors; they fall back to anonymous authentication for graceful degradation.

Personal Access Tokens

Personal Access Tokens provide enhanced security and can be created and managed in your account settings. They are ideal for API integrations, automated scripts, and CI/CD pipelines. Tokens can have different permissions, including:

  • can_create_bug_report: Allows creating bug reports
  • can_create_feature_request: Allows creating feature requests
  • can_read_release_list: Allows listing releases
  • can_create_release: Allows creating new releases dynamically via release_label
  • can_update_issue: Allows updating existing issues
  • can_list_issues: Allows listing project issues For more information about Personal Access Tokens, see: https://betahub.io/docs/account/#personal-access-tokens
Path Parameters
Name Type Description
project_id required string
issue_id required string
Header Parameters
Name Type Description
BetaHub-Project-ID required string BetaHub project ID, the same as the project_id
Request Body
multipart/form-data
  • video_clip[video] string optional The video clip file
  • video_clip[name] string optional The name of the video clip file. If set, the file will be saved with this name.
cURL
curl \
  -X POST \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "BetaHub-Project-ID: 123" \
  -F "video_clip[video]=@file.bin" \
  -F "video_clip[name]=string" \
  "https://app.betahub.io/projects/123/issues/g-123/video_clips"
Ruby
require "net/http"
require "json"

uri = URI("https://app.betahub.io/projects/123/issues/g-123/video_clips")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Post.new(uri)
request["Authorization"] = "Bearer YOUR_API_TOKEN"
request["BetaHub-Project-ID"] = "123"

response = http.request(request)
puts response.body
Python
import requests

response = requests.post(
    "https://app.betahub.io/projects/123/issues/g-123/video_clips",
    headers={"Authorization": "Bearer YOUR_API_TOKEN", "BetaHub-Project-ID": "123"}
)
print(response.json())
JavaScript
const response = await fetch("https://app.betahub.io/projects/123/issues/g-123/video_clips", {
  method: "POST",
  headers: {
    "Authorization": "Bearer YOUR_API_TOKEN",
    "BetaHub-Project-ID": "123"
  }
});
const data = await response.json();
Java
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://app.betahub.io/projects/123/issues/g-123/video_clips"))
    .header("Authorization", "Bearer YOUR_API_TOKEN")
    .header("BetaHub-Project-ID", "123")
    .header("Content-Type", "application/json")
    .POST(HttpRequest.BodyPublishers.ofString("{\"video_clip[video]\":\"string\",\"video_clip[name]\":\"string\"}"))
    .build();
HttpResponse<String> response = client.send(
    request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
Request Body
{
  "video_clip[video]": "string",
  "video_clip[name]": "string"
}
Responses
application/json
{
  "video_clip[video]": "(binary data representing a video file)"
}
Request a presigned URL for uploading a video clip directly to S3. This is the first step of the two-step direct upload process.
Authorization required
API token for accessing draft issues or performing direct uploads. Can be a JWT token returned from issue creation in draft mode, or other valid authorization tokens. Format: “Bearer TOKEN” or “FormUser tkn-TOKEN”
Path Parameters
Name Type Description
project_id required string
issue_id required string
Request Body
application/json
  • filename string required Name of the video file to upload
  • byte_size integer required Size of the file in bytes
  • checksum string required Base64-encoded MD5 checksum of the file
  • content_type string required MIME type of the video file
    video/mp4 video/quicktime video/webm video/avi video/mov
  • name string optional Optional display name for the video clip file
cURL
curl \
  -X POST \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "filename": "gameplay.mp4",
  "byte_size": 52428800,
  "checksum": "1B2M2Y8AsgTpgAmY7PhCfg==",
  "content_type": "video/mp4",
  "name": "Boss Fight Gameplay"
}' \
  "https://app.betahub.io/projects/123/issues/g-123/video_clips/presigned_upload"
Ruby
require "net/http"
require "json"

uri = URI("https://app.betahub.io/projects/123/issues/g-123/video_clips/presigned_upload")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Post.new(uri)
request["Authorization"] = "Bearer YOUR_API_TOKEN"
request["Content-Type"] = "application/json"
request.body = {
  "filename": "gameplay.mp4",
  "byte_size": 52428800,
  "checksum": "1B2M2Y8AsgTpgAmY7PhCfg==",
  "content_type": "video/mp4",
  "name": "Boss Fight Gameplay"
}

response = http.request(request)
puts response.body
Python
import requests

response = requests.post(
    "https://app.betahub.io/projects/123/issues/g-123/video_clips/presigned_upload",
    headers={"Authorization": "Bearer YOUR_API_TOKEN"},
    json={
      "filename": "gameplay.mp4",
      "byte_size": 52428800,
      "checksum": "1B2M2Y8AsgTpgAmY7PhCfg==",
      "content_type": "video/mp4",
      "name": "Boss Fight Gameplay"
    }
)
print(response.json())
JavaScript
const response = await fetch("https://app.betahub.io/projects/123/issues/g-123/video_clips/presigned_upload", {
  method: "POST",
  headers: {
    "Authorization": "Bearer YOUR_API_TOKEN",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    "filename": "gameplay.mp4",
    "byte_size": 52428800,
    "checksum": "1B2M2Y8AsgTpgAmY7PhCfg==",
    "content_type": "video/mp4",
    "name": "Boss Fight Gameplay"
  })
});
const data = await response.json();
Java
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://app.betahub.io/projects/123/issues/g-123/video_clips/presigned_upload"))
    .header("Authorization", "Bearer YOUR_API_TOKEN")
    .header("Content-Type", "application/json")
    .POST(HttpRequest.BodyPublishers.ofString("{\"filename\":\"gameplay.mp4\",\"byte_size\":52428800,\"checksum\":\"1B2M2Y8AsgTpgAmY7PhCfg==\",\"content_type\":\"video/mp4\",\"name\":\"Boss Fight Gameplay\"}"))
    .build();
HttpResponse<String> response = client.send(
    request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
Request Body
{
  "filename": "gameplay.mp4",
  "byte_size": 52428800,
  "checksum": "1B2M2Y8AsgTpgAmY7PhCfg==",
  "content_type": "video/mp4",
  "name": "Boss Fight Gameplay"
}
Responses
application/json
{
  "blob_signed_id": "string",
  "direct_upload_url": "https://example.com",
  "headers": {},
  "blob_id": 0
}
application/json
{
  "errors": [
    "string"
  ],
  "message": "string"
}
application/json
{
  "error": "string",
  "status": "string"
}
Confirm that the video file has been uploaded to S3 and attach it to the issue. This is the second step of the two-step direct upload process.
Authorization required
API token for accessing draft issues or performing direct uploads. Can be a JWT token returned from issue creation in draft mode, or other valid authorization tokens. Format: “Bearer TOKEN” or “FormUser tkn-TOKEN”
Path Parameters
Name Type Description
project_id required string
issue_id required string
Request Body
application/json
  • blob_signed_id string required Signed ID of the blob received from presigned_upload
  • name string optional Optional display name for the video clip file
cURL
curl \
  -X POST \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "blob_signed_id": "string",
  "name": "Boss Fight Gameplay"
}' \
  "https://app.betahub.io/projects/123/issues/g-123/video_clips/confirm_upload"
Ruby
require "net/http"
require "json"

uri = URI("https://app.betahub.io/projects/123/issues/g-123/video_clips/confirm_upload")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Post.new(uri)
request["Authorization"] = "Bearer YOUR_API_TOKEN"
request["Content-Type"] = "application/json"
request.body = {
  "blob_signed_id": "string",
  "name": "Boss Fight Gameplay"
}

response = http.request(request)
puts response.body
Python
import requests

response = requests.post(
    "https://app.betahub.io/projects/123/issues/g-123/video_clips/confirm_upload",
    headers={"Authorization": "Bearer YOUR_API_TOKEN"},
    json={
      "blob_signed_id": "string",
      "name": "Boss Fight Gameplay"
    }
)
print(response.json())
JavaScript
const response = await fetch("https://app.betahub.io/projects/123/issues/g-123/video_clips/confirm_upload", {
  method: "POST",
  headers: {
    "Authorization": "Bearer YOUR_API_TOKEN",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    "blob_signed_id": "string",
    "name": "Boss Fight Gameplay"
  })
});
const data = await response.json();
Java
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://app.betahub.io/projects/123/issues/g-123/video_clips/confirm_upload"))
    .header("Authorization", "Bearer YOUR_API_TOKEN")
    .header("Content-Type", "application/json")
    .POST(HttpRequest.BodyPublishers.ofString("{\"blob_signed_id\":\"string\",\"name\":\"Boss Fight Gameplay\"}"))
    .build();
HttpResponse<String> response = client.send(
    request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
Request Body
{
  "blob_signed_id": "string",
  "name": "Boss Fight Gameplay"
}
Responses
application/json
{
  "id": "string",
  "issue_id": "string",
  "created_at": "2026-03-12T10:30:00Z",
  "updated_at": "2026-03-12T10:30:00Z",
  "processing": true,
  "processed": true,
  "failed": true,
  "video_url": "https://example.com"
}
application/json
{
  "errors": [
    "string"
  ],
  "message": "string"
}
application/json
{
  "error": "string",
  "status": "string"
}

Feature Requests

Returns a paginated list of feature requests for a project, sorted by the specified criteria. By default returns publicly visible, active requests sorted by most votes (“top”).
Authorization required

Authorization header for API access. Supports multiple authentication methods:

  1. Anonymous access: FormUser anonymous - for public operations
  2. Token-based access: FormUser tkn-{token} - for authenticated operations with legacy tokens
  3. Token with Email: FormUser tkn-{token},email:{email} - creates/links virtual user by email
  4. Token with Discord ID: FormUser tkn-{token},discord_id:{discord_id} - creates/links virtual user by Discord ID
  5. Token with JWT: FormUser tkn-{token},{jwt_token} - user identification with JWT token (legacy)
  6. Personal Access Tokens: Bearer YOUR_TOKEN_HERE - recommended for API integrations

Virtual User Creation

When using email: or discord_id: formats with FormUser tokens, the system automatically creates or reuses virtual users. Virtual users are accounts created on-the-fly for form submissions without requiring full user registration. This is useful for:

  • Linking form submissions to specific individuals by email or Discord ID
  • Tracking submissions across multiple reports from the same person
  • Creating user profiles without sign-up workflows

Virtual users created this way are marked as virtual accounts and work across Issues, Feature Requests, and Support Tickets.

Validation Rules:

  • email: format must match RFC 5322 email format. Invalid emails will fall back to anonymous access.
  • discord_id: format must be numeric (digits only). Invalid discord_ids will fall back to anonymous access.
  • Invalid identifiers do not cause HTTP errors; they fall back to anonymous authentication for graceful degradation.

Personal Access Tokens

Personal Access Tokens provide enhanced security and can be created and managed in your account settings. They are ideal for API integrations, automated scripts, and CI/CD pipelines. Tokens can have different permissions, including:

  • can_create_bug_report: Allows creating bug reports
  • can_create_feature_request: Allows creating feature requests
  • can_read_release_list: Allows listing releases
  • can_create_release: Allows creating new releases dynamically via release_label
  • can_update_issue: Allows updating existing issues
  • can_list_issues: Allows listing project issues For more information about Personal Access Tokens, see: https://betahub.io/docs/account/#personal-access-tokens
Path Parameters
Name Type Description
project_id required string
Query Parameters
Name Type Description
sort optional string Sort order for feature requests. “top” sorts by votes descending, “new” by creation date, “team_picks” shows under_review/planned/started items, “completed” shows completed items, “all” shows all publicly visible items.
top new team_picks completed all
Default: top
page optional integer Page number for pagination (default: 1)
Header Parameters
Name Type Description
BetaHub-Project-ID required string BetaHub project ID, the same as the project_id
cURL
curl \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "BetaHub-Project-ID: 123" \
  "https://app.betahub.io/projects/123/feature_requests.json?sort=top&page=123"
Ruby
require "net/http"

uri = URI("https://app.betahub.io/projects/123/feature_requests.json?sort=top&page=123")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Get.new(uri)
request["Authorization"] = "Bearer YOUR_API_TOKEN"
request["BetaHub-Project-ID"] = "123"

response = http.request(request)
puts response.body
Python
import requests

response = requests.get(
    "https://app.betahub.io/projects/123/feature_requests.json?sort=top&page=123",
    headers={"Authorization": "Bearer YOUR_API_TOKEN", "BetaHub-Project-ID": "123"}
)
print(response.json())
JavaScript
const response = await fetch("https://app.betahub.io/projects/123/feature_requests.json?sort=top&page=123", {
  headers: {
    "Authorization": "Bearer YOUR_API_TOKEN",
    "BetaHub-Project-ID": "123"
  }
});
const data = await response.json();
Java
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://app.betahub.io/projects/123/feature_requests.json?sort=top&page=123"))
    .header("Authorization", "Bearer YOUR_API_TOKEN")
    .header("BetaHub-Project-ID", "123")
    .GET()
    .build();
HttpResponse<String> response = client.send(
    request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
Responses
application/json
{
  "feature_requests": [
    {
      "id": "string",
      "title": "string",
      "description": "string",
      "status": "open",
      "created_at": "2026-03-12T10:30:00Z",
      "updated_at": "2026-03-12T10:30:00Z",
      "user": {
        "id": "string",
        "name": "string"
      },
      "votes": 0,
      "voted": true,
      "url": "string"
    }
  ],
  "pagination": {
    "current_page": 0,
    "total_pages": 0,
    "total_count": 0,
    "per_page": 0
  },
  "sort": "string",
  "project_id": 0
}
application/json
{
  "error": "string",
  "status": "string"
}
No description provided.
Authorization required

Authorization header for API access. Supports multiple authentication methods:

  1. Anonymous access: FormUser anonymous - for public operations
  2. Token-based access: FormUser tkn-{token} - for authenticated operations with legacy tokens
  3. Token with Email: FormUser tkn-{token},email:{email} - creates/links virtual user by email
  4. Token with Discord ID: FormUser tkn-{token},discord_id:{discord_id} - creates/links virtual user by Discord ID
  5. Token with JWT: FormUser tkn-{token},{jwt_token} - user identification with JWT token (legacy)
  6. Personal Access Tokens: Bearer YOUR_TOKEN_HERE - recommended for API integrations

Virtual User Creation

When using email: or discord_id: formats with FormUser tokens, the system automatically creates or reuses virtual users. Virtual users are accounts created on-the-fly for form submissions without requiring full user registration. This is useful for:

  • Linking form submissions to specific individuals by email or Discord ID
  • Tracking submissions across multiple reports from the same person
  • Creating user profiles without sign-up workflows

Virtual users created this way are marked as virtual accounts and work across Issues, Feature Requests, and Support Tickets.

Validation Rules:

  • email: format must match RFC 5322 email format. Invalid emails will fall back to anonymous access.
  • discord_id: format must be numeric (digits only). Invalid discord_ids will fall back to anonymous access.
  • Invalid identifiers do not cause HTTP errors; they fall back to anonymous authentication for graceful degradation.

Personal Access Tokens

Personal Access Tokens provide enhanced security and can be created and managed in your account settings. They are ideal for API integrations, automated scripts, and CI/CD pipelines. Tokens can have different permissions, including:

  • can_create_bug_report: Allows creating bug reports
  • can_create_feature_request: Allows creating feature requests
  • can_read_release_list: Allows listing releases
  • can_create_release: Allows creating new releases dynamically via release_label
  • can_update_issue: Allows updating existing issues
  • can_list_issues: Allows listing project issues For more information about Personal Access Tokens, see: https://betahub.io/docs/account/#personal-access-tokens
Path Parameters
Name Type Description
project_id required string
Header Parameters
Name Type Description
BetaHub-Project-ID required string BetaHub project ID, the same as the project_id
Request Body
application/x-www-form-urlencoded
  • feature_request[description] string required Description of the feature request.
  • feature_request[title] string optional Title of the feature request. Only available for project developers or admins.
  • feature_request[custom][FIELD_IDENT] string optional Custom field values for the suggestion. Replace FIELD_IDENT with the field’s identifier (e.g., feature_request[custom][category], feature_request[custom][priority_level]). See the issue creation endpoint documentation for details on field types, validation, and JSON format. Use the project’s Custom Fields settings to find available identifiers.
  • draft boolean optional When set to true, creates the feature request in hidden (draft) status. Draft feature requests are not visible until published.
  • user[discord_id] string optional Discord ID of the user creating the feature request. Only used when authenticated as a Discord bot.
  • user[discord_username] string optional Discord username of the user creating the feature request. Only used when authenticated as a Discord bot.
  • user[discord_discriminator] string optional Discord discriminator of the user creating the feature request. Only used when authenticated as a Discord bot.
cURL
curl \
  -X POST \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "BetaHub-Project-ID: 123" \
  -d "feature_request[description]=Example description" \
  -d "feature_request[title]=Example title" \
  -d "feature_request[custom][FIELD_IDENT]=string" \
  -d "draft=true" \
  -d "user[discord_id]=string" \
  -d "user[discord_username]=string" \
  "https://app.betahub.io/projects/123/feature_requests.json"
Ruby
require "net/http"
require "json"

uri = URI("https://app.betahub.io/projects/123/feature_requests.json")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Post.new(uri)
request["Authorization"] = "Bearer YOUR_API_TOKEN"
request["BetaHub-Project-ID"] = "123"
request.set_form_data({
  "feature_request[description]" => "Example description",
  "feature_request[title]" => "Example title",
  "feature_request[custom][FIELD_IDENT]" => "string",
  "draft" => "true",
  "user[discord_id]" => "string",
  "user[discord_username]" => "string"
})

response = http.request(request)
puts response.body
Python
import requests

response = requests.post(
    "https://app.betahub.io/projects/123/feature_requests.json",
    headers={"Authorization": "Bearer YOUR_API_TOKEN", "BetaHub-Project-ID": "123"},
    data={"feature_request[description]": "Example description", "feature_request[title]": "Example title", "feature_request[custom][FIELD_IDENT]": "string", "draft": "true", "user[discord_id]": "string", "user[discord_username]": "string"}
)
print(response.json())
JavaScript
const response = await fetch("https://app.betahub.io/projects/123/feature_requests.json", {
  method: "POST",
  headers: {
    "Authorization": "Bearer YOUR_API_TOKEN",
    "BetaHub-Project-ID": "123"
  }
});
const data = await response.json();
Java
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://app.betahub.io/projects/123/feature_requests.json"))
    .header("Authorization", "Bearer YOUR_API_TOKEN")
    .header("BetaHub-Project-ID", "123")
    .header("Content-Type", "application/json")
    .POST(HttpRequest.BodyPublishers.ofString("{\"feature_request[description]\":\"string\",\"feature_request[title]\":\"string\",\"feature_request[custom][FIELD_IDENT]\":\"string\",\"draft\":true,\"user[discord_id]\":\"string\",\"user[discord_username]\":\"string\",\"user[discord_discriminator]\":\"string\"}"))
    .build();
HttpResponse<String> response = client.send(
    request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
Request Body
{
  "feature_request[description]": "string",
  "feature_request[title]": "string",
  "feature_request[custom][FIELD_IDENT]": "string",
  "draft": true,
  "user[discord_id]": "string",
  "user[discord_username]": "string",
  "user[discord_discriminator]": "string"
}
Responses
application/json
{
  "feature_request[description]": "Add a dark mode to the app",
  "user[discord_id]": "123456789",
  "user[discord_username]": "username",
  "user[discord_discriminator]": "1234"
}
application/json
{
  "error": "string",
  "status": "string"
}
Searches for feature requests (also known as suggestions) within a project. Uses full-text search powered by Meilisearch to find matching feature requests based on the query string. Returns matching titles for autocomplete functionality or full feature request objects for detailed results. Note: Only searches among publicly visible, active feature requests (excludes pending moderation, rejected, muted, duplicate, and split requests).
Authorization required

Authorization header for API access. Supports multiple authentication methods:

  1. Anonymous access: FormUser anonymous - for public operations
  2. Token-based access: FormUser tkn-{token} - for authenticated operations with legacy tokens
  3. Token with Email: FormUser tkn-{token},email:{email} - creates/links virtual user by email
  4. Token with Discord ID: FormUser tkn-{token},discord_id:{discord_id} - creates/links virtual user by Discord ID
  5. Token with JWT: FormUser tkn-{token},{jwt_token} - user identification with JWT token (legacy)
  6. Personal Access Tokens: Bearer YOUR_TOKEN_HERE - recommended for API integrations

Virtual User Creation

When using email: or discord_id: formats with FormUser tokens, the system automatically creates or reuses virtual users. Virtual users are accounts created on-the-fly for form submissions without requiring full user registration. This is useful for:

  • Linking form submissions to specific individuals by email or Discord ID
  • Tracking submissions across multiple reports from the same person
  • Creating user profiles without sign-up workflows

Virtual users created this way are marked as virtual accounts and work across Issues, Feature Requests, and Support Tickets.

Validation Rules:

  • email: format must match RFC 5322 email format. Invalid emails will fall back to anonymous access.
  • discord_id: format must be numeric (digits only). Invalid discord_ids will fall back to anonymous access.
  • Invalid identifiers do not cause HTTP errors; they fall back to anonymous authentication for graceful degradation.

Personal Access Tokens

Personal Access Tokens provide enhanced security and can be created and managed in your account settings. They are ideal for API integrations, automated scripts, and CI/CD pipelines. Tokens can have different permissions, including:

  • can_create_bug_report: Allows creating bug reports
  • can_create_feature_request: Allows creating feature requests
  • can_read_release_list: Allows listing releases
  • can_create_release: Allows creating new releases dynamically via release_label
  • can_update_issue: Allows updating existing issues
  • can_list_issues: Allows listing project issues For more information about Personal Access Tokens, see: https://betahub.io/docs/account/#personal-access-tokens
Path Parameters
Name Type Description
project_id required string
Query Parameters
Name Type Description
query required string The search query string to match against feature request titles and descriptions
skip_ids optional string Comma-separated list of feature request IDs to exclude from results
partial optional string When set to ‘true’, returns limited results optimized for autocomplete (max 4 results)
true false
scoped_id optional string Instead of searching, find a specific feature request by its scoped ID (e.g., “123” or “fr-456”)
Header Parameters
Name Type Description
BetaHub-Project-ID required string BetaHub project ID, the same as the project_id
cURL
curl \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "BetaHub-Project-ID: 123" \
  "https://app.betahub.io/projects/123/feature_requests/search.json?query=example&skip_ids=123&partial=true&scoped_id=123"
Ruby
require "net/http"

uri = URI("https://app.betahub.io/projects/123/feature_requests/search.json?query=example&skip_ids=123&partial=true&scoped_id=123")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Get.new(uri)
request["Authorization"] = "Bearer YOUR_API_TOKEN"
request["BetaHub-Project-ID"] = "123"

response = http.request(request)
puts response.body
Python
import requests

response = requests.get(
    "https://app.betahub.io/projects/123/feature_requests/search.json?query=example&skip_ids=123&partial=true&scoped_id=123",
    headers={"Authorization": "Bearer YOUR_API_TOKEN", "BetaHub-Project-ID": "123"}
)
print(response.json())
JavaScript
const response = await fetch("https://app.betahub.io/projects/123/feature_requests/search.json?query=example&skip_ids=123&partial=true&scoped_id=123", {
  headers: {
    "Authorization": "Bearer YOUR_API_TOKEN",
    "BetaHub-Project-ID": "123"
  }
});
const data = await response.json();
Java
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://app.betahub.io/projects/123/feature_requests/search.json?query=example&skip_ids=123&partial=true&scoped_id=123"))
    .header("Authorization", "Bearer YOUR_API_TOKEN")
    .header("BetaHub-Project-ID", "123")
    .GET()
    .build();
HttpResponse<String> response = client.send(
    request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
Responses
application/json
{
  "feature_requests": [
    {
      "id": "1234abc",
      "title": "Add dark mode support",
      "status": "open",
      "created_at": "2024-10-03T12:34:56Z"
    }
  ],
  "pagination": {
    "current_page": 1,
    "per_page": 25,
    "total_pages": 2,
    "total_count": 42
  },
  "sort": "top",
  "project_id": 123,
  "votes": 42,
  "voted": false,
  "url": "https://app.betahub.io/projects/1/feature_requests/1234abc"
}
application/json
{
  "error": "string",
  "status": "string"
}
application/json
{
  "error": "string",
  "status": "string"
}
Returns detailed information about a specific feature request, including vote count, duplicate information, and attachments.
Authorization required

Authorization header for API access. Supports multiple authentication methods:

  1. Anonymous access: FormUser anonymous - for public operations
  2. Token-based access: FormUser tkn-{token} - for authenticated operations with legacy tokens
  3. Token with Email: FormUser tkn-{token},email:{email} - creates/links virtual user by email
  4. Token with Discord ID: FormUser tkn-{token},discord_id:{discord_id} - creates/links virtual user by Discord ID
  5. Token with JWT: FormUser tkn-{token},{jwt_token} - user identification with JWT token (legacy)
  6. Personal Access Tokens: Bearer YOUR_TOKEN_HERE - recommended for API integrations

Virtual User Creation

When using email: or discord_id: formats with FormUser tokens, the system automatically creates or reuses virtual users. Virtual users are accounts created on-the-fly for form submissions without requiring full user registration. This is useful for:

  • Linking form submissions to specific individuals by email or Discord ID
  • Tracking submissions across multiple reports from the same person
  • Creating user profiles without sign-up workflows

Virtual users created this way are marked as virtual accounts and work across Issues, Feature Requests, and Support Tickets.

Validation Rules:

  • email: format must match RFC 5322 email format. Invalid emails will fall back to anonymous access.
  • discord_id: format must be numeric (digits only). Invalid discord_ids will fall back to anonymous access.
  • Invalid identifiers do not cause HTTP errors; they fall back to anonymous authentication for graceful degradation.

Personal Access Tokens

Personal Access Tokens provide enhanced security and can be created and managed in your account settings. They are ideal for API integrations, automated scripts, and CI/CD pipelines. Tokens can have different permissions, including:

  • can_create_bug_report: Allows creating bug reports
  • can_create_feature_request: Allows creating feature requests
  • can_read_release_list: Allows listing releases
  • can_create_release: Allows creating new releases dynamically via release_label
  • can_update_issue: Allows updating existing issues
  • can_list_issues: Allows listing project issues For more information about Personal Access Tokens, see: https://betahub.io/docs/account/#personal-access-tokens
Path Parameters
Name Type Description
project_id required string
id required string The feature request ID or scoped ID
Header Parameters
Name Type Description
BetaHub-Project-ID required string BetaHub project ID, the same as the project_id
cURL
curl \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "BetaHub-Project-ID: 123" \
  "https://app.betahub.io/projects/123/feature_requests/123.json"
Ruby
require "net/http"

uri = URI("https://app.betahub.io/projects/123/feature_requests/123.json")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Get.new(uri)
request["Authorization"] = "Bearer YOUR_API_TOKEN"
request["BetaHub-Project-ID"] = "123"

response = http.request(request)
puts response.body
Python
import requests

response = requests.get(
    "https://app.betahub.io/projects/123/feature_requests/123.json",
    headers={"Authorization": "Bearer YOUR_API_TOKEN", "BetaHub-Project-ID": "123"}
)
print(response.json())
JavaScript
const response = await fetch("https://app.betahub.io/projects/123/feature_requests/123.json", {
  headers: {
    "Authorization": "Bearer YOUR_API_TOKEN",
    "BetaHub-Project-ID": "123"
  }
});
const data = await response.json();
Java
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://app.betahub.io/projects/123/feature_requests/123.json"))
    .header("Authorization", "Bearer YOUR_API_TOKEN")
    .header("BetaHub-Project-ID", "123")
    .GET()
    .build();
HttpResponse<String> response = client.send(
    request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
Responses
application/json
{
  "id": "string",
  "title": "string",
  "description": "string",
  "status": "open",
  "created_at": "2026-03-12T10:30:00Z",
  "updated_at": "2026-03-12T10:30:00Z",
  "user": {
    "id": "string",
    "name": "string"
  },
  "votes": 0,
  "voted": true,
  "url": "string"
}
application/json
{
  "error": "string",
  "status": "string"
}
application/json
{
  "error": "string",
  "status": "string"
}
Sets or updates the contact information (email or Discord ID) for a feature request. This is primarily used in the draft flow to capture user contact details. Either email or discord_id must be provided. This creates a virtual user who will receive notifications about the feature request.
Authorization required

Authorization header for API access. Supports multiple authentication methods:

  1. Anonymous access: FormUser anonymous - for public operations
  2. Token-based access: FormUser tkn-{token} - for authenticated operations with legacy tokens
  3. Token with Email: FormUser tkn-{token},email:{email} - creates/links virtual user by email
  4. Token with Discord ID: FormUser tkn-{token},discord_id:{discord_id} - creates/links virtual user by Discord ID
  5. Token with JWT: FormUser tkn-{token},{jwt_token} - user identification with JWT token (legacy)
  6. Personal Access Tokens: Bearer YOUR_TOKEN_HERE - recommended for API integrations

Virtual User Creation

When using email: or discord_id: formats with FormUser tokens, the system automatically creates or reuses virtual users. Virtual users are accounts created on-the-fly for form submissions without requiring full user registration. This is useful for:

  • Linking form submissions to specific individuals by email or Discord ID
  • Tracking submissions across multiple reports from the same person
  • Creating user profiles without sign-up workflows

Virtual users created this way are marked as virtual accounts and work across Issues, Feature Requests, and Support Tickets.

Validation Rules:

  • email: format must match RFC 5322 email format. Invalid emails will fall back to anonymous access.
  • discord_id: format must be numeric (digits only). Invalid discord_ids will fall back to anonymous access.
  • Invalid identifiers do not cause HTTP errors; they fall back to anonymous authentication for graceful degradation.

Personal Access Tokens

Personal Access Tokens provide enhanced security and can be created and managed in your account settings. They are ideal for API integrations, automated scripts, and CI/CD pipelines. Tokens can have different permissions, including:

  • can_create_bug_report: Allows creating bug reports
  • can_create_feature_request: Allows creating feature requests
  • can_read_release_list: Allows listing releases
  • can_create_release: Allows creating new releases dynamically via release_label
  • can_update_issue: Allows updating existing issues
  • can_list_issues: Allows listing project issues For more information about Personal Access Tokens, see: https://betahub.io/docs/account/#personal-access-tokens
Path Parameters
Name Type Description
project_id required string
id required string The feature request ID or scoped ID
Header Parameters
Name Type Description
BetaHub-Project-ID required string BetaHub project ID, the same as the project_id
Request Body
application/json
  • email string optional Email address of the user. Either email or discord_id is required.
  • discord_id string optional Discord user ID (numeric string). Either email or discord_id is required.
cURL
curl \
  -X POST \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "BetaHub-Project-ID: 123" \
  -H "Content-Type: application/json" \
  -d '{
  "email": "user@example.com",
  "discord_id": "user@example.com"
}' \
  "https://app.betahub.io/projects/123/feature_requests/123/set_contact_info"
Ruby
require "net/http"
require "json"

uri = URI("https://app.betahub.io/projects/123/feature_requests/123/set_contact_info")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Post.new(uri)
request["Authorization"] = "Bearer YOUR_API_TOKEN"
request["BetaHub-Project-ID"] = "123"
request["Content-Type"] = "application/json"
request.body = {
  "email": "user@example.com",
  "discord_id": "user@example.com"
}

response = http.request(request)
puts response.body
Python
import requests

response = requests.post(
    "https://app.betahub.io/projects/123/feature_requests/123/set_contact_info",
    headers={"Authorization": "Bearer YOUR_API_TOKEN", "BetaHub-Project-ID": "123"},
    json={
      "email": "user@example.com",
      "discord_id": "user@example.com"
    }
)
print(response.json())
JavaScript
const response = await fetch("https://app.betahub.io/projects/123/feature_requests/123/set_contact_info", {
  method: "POST",
  headers: {
    "Authorization": "Bearer YOUR_API_TOKEN",
    "BetaHub-Project-ID": "123",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    "email": "user@example.com",
    "discord_id": "user@example.com"
  })
});
const data = await response.json();
Java
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://app.betahub.io/projects/123/feature_requests/123/set_contact_info"))
    .header("Authorization", "Bearer YOUR_API_TOKEN")
    .header("BetaHub-Project-ID", "123")
    .header("Content-Type", "application/json")
    .POST(HttpRequest.BodyPublishers.ofString("{\"email\":\"user@example.com\",\"discord_id\":\"user@example.com\"}"))
    .build();
HttpResponse<String> response = client.send(
    request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
Request Body
{
  "email": "user@example.com",
  "discord_id": "user@example.com"
}
Responses
application/json
{
  "success": true,
  "message": "Contact information assigned successfully",
  "feature_request_id": "1234",
  "user": {
    "id": 56,
    "email": "user@example.com",
    "discord_id": null,
    "virtual": true
  }
}
application/json
{
  "error": "string",
  "status": "string"
}
application/json
{
  "error": "string",
  "status": "string"
}
application/json
{
  "error": "string",
  "status": "string"
}
Publishes a draft (hidden) feature request by changing its status from hidden to open. This makes the feature request visible to other users. Typically used at the end of the draft flow when the user completes their submission.
Authorization required

Authorization header for API access. Supports multiple authentication methods:

  1. Anonymous access: FormUser anonymous - for public operations
  2. Token-based access: FormUser tkn-{token} - for authenticated operations with legacy tokens
  3. Token with Email: FormUser tkn-{token},email:{email} - creates/links virtual user by email
  4. Token with Discord ID: FormUser tkn-{token},discord_id:{discord_id} - creates/links virtual user by Discord ID
  5. Token with JWT: FormUser tkn-{token},{jwt_token} - user identification with JWT token (legacy)
  6. Personal Access Tokens: Bearer YOUR_TOKEN_HERE - recommended for API integrations

Virtual User Creation

When using email: or discord_id: formats with FormUser tokens, the system automatically creates or reuses virtual users. Virtual users are accounts created on-the-fly for form submissions without requiring full user registration. This is useful for:

  • Linking form submissions to specific individuals by email or Discord ID
  • Tracking submissions across multiple reports from the same person
  • Creating user profiles without sign-up workflows

Virtual users created this way are marked as virtual accounts and work across Issues, Feature Requests, and Support Tickets.

Validation Rules:

  • email: format must match RFC 5322 email format. Invalid emails will fall back to anonymous access.
  • discord_id: format must be numeric (digits only). Invalid discord_ids will fall back to anonymous access.
  • Invalid identifiers do not cause HTTP errors; they fall back to anonymous authentication for graceful degradation.

Personal Access Tokens

Personal Access Tokens provide enhanced security and can be created and managed in your account settings. They are ideal for API integrations, automated scripts, and CI/CD pipelines. Tokens can have different permissions, including:

  • can_create_bug_report: Allows creating bug reports
  • can_create_feature_request: Allows creating feature requests
  • can_read_release_list: Allows listing releases
  • can_create_release: Allows creating new releases dynamically via release_label
  • can_update_issue: Allows updating existing issues
  • can_list_issues: Allows listing project issues For more information about Personal Access Tokens, see: https://betahub.io/docs/account/#personal-access-tokens
Path Parameters
Name Type Description
project_id required string
id required string The feature request ID or scoped ID
Header Parameters
Name Type Description
BetaHub-Project-ID required string BetaHub project ID, the same as the project_id
cURL
curl \
  -X POST \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "BetaHub-Project-ID: 123" \
  "https://app.betahub.io/projects/123/feature_requests/123/publish"
Ruby
require "net/http"

uri = URI("https://app.betahub.io/projects/123/feature_requests/123/publish")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Post.new(uri)
request["Authorization"] = "Bearer YOUR_API_TOKEN"
request["BetaHub-Project-ID"] = "123"

response = http.request(request)
puts response.body
Python
import requests

response = requests.post(
    "https://app.betahub.io/projects/123/feature_requests/123/publish",
    headers={"Authorization": "Bearer YOUR_API_TOKEN", "BetaHub-Project-ID": "123"}
)
print(response.json())
JavaScript
const response = await fetch("https://app.betahub.io/projects/123/feature_requests/123/publish", {
  method: "POST",
  headers: {
    "Authorization": "Bearer YOUR_API_TOKEN",
    "BetaHub-Project-ID": "123"
  }
});
const data = await response.json();
Java
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://app.betahub.io/projects/123/feature_requests/123/publish"))
    .header("Authorization", "Bearer YOUR_API_TOKEN")
    .header("BetaHub-Project-ID", "123")
    .method("POST", HttpRequest.BodyPublishers.noBody())
    .build();
HttpResponse<String> response = client.send(
    request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
Responses
application/json
{
  "success": true
}
application/json
{
  "error": "string",
  "status": "string"
}
application/json
{
  "error": "string",
  "status": "string"
}

Support Tickets

Searches for support tickets within a project using a simple query string. Returns matching tickets with basic information (id and title) for autocomplete functionality. Uses ILIKE pattern matching on title and description fields. Results are limited to 10 tickets and filtered based on user permissions.
Authorization required

Authorization header for API access. Supports multiple authentication methods:

  1. Anonymous access: FormUser anonymous - for public operations
  2. Token-based access: FormUser tkn-{token} - for authenticated operations with legacy tokens
  3. Token with Email: FormUser tkn-{token},email:{email} - creates/links virtual user by email
  4. Token with Discord ID: FormUser tkn-{token},discord_id:{discord_id} - creates/links virtual user by Discord ID
  5. Token with JWT: FormUser tkn-{token},{jwt_token} - user identification with JWT token (legacy)
  6. Personal Access Tokens: Bearer YOUR_TOKEN_HERE - recommended for API integrations

Virtual User Creation

When using email: or discord_id: formats with FormUser tokens, the system automatically creates or reuses virtual users. Virtual users are accounts created on-the-fly for form submissions without requiring full user registration. This is useful for:

  • Linking form submissions to specific individuals by email or Discord ID
  • Tracking submissions across multiple reports from the same person
  • Creating user profiles without sign-up workflows

Virtual users created this way are marked as virtual accounts and work across Issues, Feature Requests, and Support Tickets.

Validation Rules:

  • email: format must match RFC 5322 email format. Invalid emails will fall back to anonymous access.
  • discord_id: format must be numeric (digits only). Invalid discord_ids will fall back to anonymous access.
  • Invalid identifiers do not cause HTTP errors; they fall back to anonymous authentication for graceful degradation.

Personal Access Tokens

Personal Access Tokens provide enhanced security and can be created and managed in your account settings. They are ideal for API integrations, automated scripts, and CI/CD pipelines. Tokens can have different permissions, including:

  • can_create_bug_report: Allows creating bug reports
  • can_create_feature_request: Allows creating feature requests
  • can_read_release_list: Allows listing releases
  • can_create_release: Allows creating new releases dynamically via release_label
  • can_update_issue: Allows updating existing issues
  • can_list_issues: Allows listing project issues For more information about Personal Access Tokens, see: https://betahub.io/docs/account/#personal-access-tokens
Path Parameters
Name Type Description
project_id required string
Query Parameters
Name Type Description
query required string The search query string to match against ticket titles and descriptions
Header Parameters
Name Type Description
BetaHub-Project-ID required string BetaHub project ID, the same as the project_id
cURL
curl \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "BetaHub-Project-ID: 123" \
  "https://app.betahub.io/projects/123/tickets/search.json?query=example"
Ruby
require "net/http"

uri = URI("https://app.betahub.io/projects/123/tickets/search.json?query=example")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Get.new(uri)
request["Authorization"] = "Bearer YOUR_API_TOKEN"
request["BetaHub-Project-ID"] = "123"

response = http.request(request)
puts response.body
Python
import requests

response = requests.get(
    "https://app.betahub.io/projects/123/tickets/search.json?query=example",
    headers={"Authorization": "Bearer YOUR_API_TOKEN", "BetaHub-Project-ID": "123"}
)
print(response.json())
JavaScript
const response = await fetch("https://app.betahub.io/projects/123/tickets/search.json?query=example", {
  headers: {
    "Authorization": "Bearer YOUR_API_TOKEN",
    "BetaHub-Project-ID": "123"
  }
});
const data = await response.json();
Java
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://app.betahub.io/projects/123/tickets/search.json?query=example"))
    .header("Authorization", "Bearer YOUR_API_TOKEN")
    .header("BetaHub-Project-ID", "123")
    .GET()
    .build();
HttpResponse<String> response = client.send(
    request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
Responses
application/json
[
  {
    "id": "123",
    "title": "Cannot access user settings"
  },
  {
    "id": "456",
    "title": "Password reset not working"
  }
]
application/json
{
  "error": "string",
  "status": "string"
}

Creates a new support ticket for a project. Support tickets are used for customer support, help requests, and technical assistance.

Authentication Support:

  • FormUser with Email: Use FormUser tkn-{token},email:{email} header OR provide ticket[reporter_email] in form data to create/link virtual user by email - FormUser with Discord ID: Use FormUser tkn-{token},discord_id:{discord_id} header to create/link virtual user by Discord ID - Discord Bot: Can create tickets on behalf of Discord users by providing discord_id, discord_username, and discord_discriminator in form data - Authenticated Users: Tickets are created with current_user as reporter - Anonymous Users: Must provide reporter_email in form data or email/discord_id in auth header. Anonymous ticket creation without contact info is not allowed.

    Attachments: Tickets can include file attachments (images, documents, logs) using multipart/form-data. Multiple files can be attached by providing the attachments parameter multiple times.

Authorization required

Authorization header for API access. Supports multiple authentication methods:

  1. Anonymous access: FormUser anonymous - for public operations
  2. Token-based access: FormUser tkn-{token} - for authenticated operations with legacy tokens
  3. Token with Email: FormUser tkn-{token},email:{email} - creates/links virtual user by email
  4. Token with Discord ID: FormUser tkn-{token},discord_id:{discord_id} - creates/links virtual user by Discord ID
  5. Token with JWT: FormUser tkn-{token},{jwt_token} - user identification with JWT token (legacy)
  6. Personal Access Tokens: Bearer YOUR_TOKEN_HERE - recommended for API integrations

Virtual User Creation

When using email: or discord_id: formats with FormUser tokens, the system automatically creates or reuses virtual users. Virtual users are accounts created on-the-fly for form submissions without requiring full user registration. This is useful for:

  • Linking form submissions to specific individuals by email or Discord ID
  • Tracking submissions across multiple reports from the same person
  • Creating user profiles without sign-up workflows

Virtual users created this way are marked as virtual accounts and work across Issues, Feature Requests, and Support Tickets.

Validation Rules:

  • email: format must match RFC 5322 email format. Invalid emails will fall back to anonymous access.
  • discord_id: format must be numeric (digits only). Invalid discord_ids will fall back to anonymous access.
  • Invalid identifiers do not cause HTTP errors; they fall back to anonymous authentication for graceful degradation.

Personal Access Tokens

Personal Access Tokens provide enhanced security and can be created and managed in your account settings. They are ideal for API integrations, automated scripts, and CI/CD pipelines. Tokens can have different permissions, including:

  • can_create_bug_report: Allows creating bug reports
  • can_create_feature_request: Allows creating feature requests
  • can_read_release_list: Allows listing releases
  • can_create_release: Allows creating new releases dynamically via release_label
  • can_update_issue: Allows updating existing issues
  • can_list_issues: Allows listing project issues For more information about Personal Access Tokens, see: https://betahub.io/docs/account/#personal-access-tokens
Path Parameters
Name Type Description
project_id required string
Header Parameters
Name Type Description
BetaHub-Project-ID required string BetaHub project ID, the same as the project_id
Request Body
multipart/form-data
  • ticket[description] string required Description of the support ticket. Required.
  • ticket[title] string optional Title of the ticket. If not provided, will be auto-generated from description.
  • ticket[priority] string optional Priority level. Defaults to ‘low’.
    low medium high critical
  • ticket[attachments][] array[string] optional File attachments (images, documents, logs, etc.). Can be provided multiple times for multiple files.
  • ticket[custom][FIELD_IDENT] string optional Custom field values for the ticket. Replace FIELD_IDENT with the field’s identifier (e.g., ticket[custom][platform], ticket[custom][priority_level]). See the issue creation endpoint documentation for details on field types, validation, and JSON format. Use the project’s Custom Fields settings to find available identifiers.
  • ticket[reporter_email] string optional Email address of the ticket reporter. Optional for authenticated users and Discord bot. Required for anonymous FormUser submissions (when auth header doesn’t include email/discord_id). If provided, a virtual user will be created/found with this email. Form field takes precedence over auth header email.
  • user[discord_id] string optional Discord ID of the user creating the ticket. Only used when authenticated as a Discord bot.
  • user[discord_username] string optional Discord username. Only used when authenticated as a Discord bot.
  • user[discord_discriminator] string optional Discord discriminator. Only used when authenticated as a Discord bot.
cURL
curl \
  -X POST \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "BetaHub-Project-ID: 123" \
  -F "ticket[description]=Example description" \
  -F "ticket[title]=Example title" \
  -F "ticket[priority]=low" \
  -F "ticket[attachments][]=string" \
  "https://app.betahub.io/projects/123/tickets.json"
Ruby
require "net/http"
require "json"

uri = URI("https://app.betahub.io/projects/123/tickets.json")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Post.new(uri)
request["Authorization"] = "Bearer YOUR_API_TOKEN"
request["BetaHub-Project-ID"] = "123"

response = http.request(request)
puts response.body
Python
import requests

response = requests.post(
    "https://app.betahub.io/projects/123/tickets.json",
    headers={"Authorization": "Bearer YOUR_API_TOKEN", "BetaHub-Project-ID": "123"}
)
print(response.json())
JavaScript
const response = await fetch("https://app.betahub.io/projects/123/tickets.json", {
  method: "POST",
  headers: {
    "Authorization": "Bearer YOUR_API_TOKEN",
    "BetaHub-Project-ID": "123"
  }
});
const data = await response.json();
Java
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://app.betahub.io/projects/123/tickets.json"))
    .header("Authorization", "Bearer YOUR_API_TOKEN")
    .header("BetaHub-Project-ID", "123")
    .header("Content-Type", "application/json")
    .POST(HttpRequest.BodyPublishers.ofString("{\"ticket[description]\":\"string\",\"ticket[title]\":\"string\",\"ticket[priority]\":\"low\",\"ticket[attachments][]\":[\"string\"],\"ticket[custom][FIELD_IDENT]\":\"string\",\"ticket[reporter_email]\":\"user@example.com\",\"user[discord_id]\":\"string\",\"user[discord_username]\":\"string\",\"user[discord_discriminator]\":\"string\"}"))
    .build();
HttpResponse<String> response = client.send(
    request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
Request Body
{
  "ticket[description]": "string",
  "ticket[title]": "string",
  "ticket[priority]": "low",
  "ticket[attachments][]": [
    "string"
  ],
  "ticket[custom][FIELD_IDENT]": "string",
  "ticket[reporter_email]": "user@example.com",
  "user[discord_id]": "string",
  "user[discord_username]": "string",
  "user[discord_discriminator]": "string"
}
Responses
application/json
{
  "ticket[description]": "I need help resetting my password",
  "ticket[priority]": "high"
}
application/json
{
  "error": "Description can't be blank"
}
application/json
{
  "error": "Authentication required for creating support tickets"
}
application/json
{
  "error": "string",
  "status": "string"
}
Retrieves detailed information about a specific support ticket, including all attachments, status, priority, and assignment information.
Authorization required

Authorization header for API access. Supports multiple authentication methods:

  1. Anonymous access: FormUser anonymous - for public operations
  2. Token-based access: FormUser tkn-{token} - for authenticated operations with legacy tokens
  3. Token with Email: FormUser tkn-{token},email:{email} - creates/links virtual user by email
  4. Token with Discord ID: FormUser tkn-{token},discord_id:{discord_id} - creates/links virtual user by Discord ID
  5. Token with JWT: FormUser tkn-{token},{jwt_token} - user identification with JWT token (legacy)
  6. Personal Access Tokens: Bearer YOUR_TOKEN_HERE - recommended for API integrations

Virtual User Creation

When using email: or discord_id: formats with FormUser tokens, the system automatically creates or reuses virtual users. Virtual users are accounts created on-the-fly for form submissions without requiring full user registration. This is useful for:

  • Linking form submissions to specific individuals by email or Discord ID
  • Tracking submissions across multiple reports from the same person
  • Creating user profiles without sign-up workflows

Virtual users created this way are marked as virtual accounts and work across Issues, Feature Requests, and Support Tickets.

Validation Rules:

  • email: format must match RFC 5322 email format. Invalid emails will fall back to anonymous access.
  • discord_id: format must be numeric (digits only). Invalid discord_ids will fall back to anonymous access.
  • Invalid identifiers do not cause HTTP errors; they fall back to anonymous authentication for graceful degradation.

Personal Access Tokens

Personal Access Tokens provide enhanced security and can be created and managed in your account settings. They are ideal for API integrations, automated scripts, and CI/CD pipelines. Tokens can have different permissions, including:

  • can_create_bug_report: Allows creating bug reports
  • can_create_feature_request: Allows creating feature requests
  • can_read_release_list: Allows listing releases
  • can_create_release: Allows creating new releases dynamically via release_label
  • can_update_issue: Allows updating existing issues
  • can_list_issues: Allows listing project issues For more information about Personal Access Tokens, see: https://betahub.io/docs/account/#personal-access-tokens
Path Parameters
Name Type Description
project_id required string
id required string The ticket ID. Can be a numeric ID or scoped ID format.
Header Parameters
Name Type Description
BetaHub-Project-ID required string BetaHub project ID, the same as the project_id
cURL
curl \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "BetaHub-Project-ID: 123" \
  "https://app.betahub.io/projects/123/tickets/123.json"
Ruby
require "net/http"

uri = URI("https://app.betahub.io/projects/123/tickets/123.json")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Get.new(uri)
request["Authorization"] = "Bearer YOUR_API_TOKEN"
request["BetaHub-Project-ID"] = "123"

response = http.request(request)
puts response.body
Python
import requests

response = requests.get(
    "https://app.betahub.io/projects/123/tickets/123.json",
    headers={"Authorization": "Bearer YOUR_API_TOKEN", "BetaHub-Project-ID": "123"}
)
print(response.json())
JavaScript
const response = await fetch("https://app.betahub.io/projects/123/tickets/123.json", {
  headers: {
    "Authorization": "Bearer YOUR_API_TOKEN",
    "BetaHub-Project-ID": "123"
  }
});
const data = await response.json();
Java
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://app.betahub.io/projects/123/tickets/123.json"))
    .header("Authorization", "Bearer YOUR_API_TOKEN")
    .header("BetaHub-Project-ID", "123")
    .GET()
    .build();
HttpResponse<String> response = client.send(
    request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
Responses
application/json
{
  "id": "123",
  "title": "Password reset assistance needed",
  "description": "I need help resetting my password",
  "status": "open",
  "priority": "high",
  "created_at": "2024-10-06T10:00:00Z",
  "updated_at": "2024-10-06T10:30:00Z",
  "reporter": {
    "id": "456",
    "name": "John Doe"
  },
  "assigned_to": {
    "id": "789",
    "name": "Support Agent"
  },
  "url": "https://app.betahub.io/projects/1/tickets/123",
  "attachments": [
    {
      "id": "101",
      "filename": "screenshot.png",
      "url": "https://cdn.betahub.io/attachments/101/screenshot.png",
      "content_type": "image/png",
      "file_type": "image",
      "size_bytes": 245678,
      "user": {
        "id": "456",
        "name": "John Doe"
      }
    }
  ]
}
application/json
{
  "error": "string",
  "status": "string"
}
application/json
{
  "error": "string",
  "status": "string"
}

Updates an existing support ticket with new information. This endpoint supports comprehensive ticket management including:

Supported Operations:

  • Update ticket fields (title, description, status, priority, assignment) - Add new attachments
  • Upload new files to the ticket - Remove existing attachments
  • Delete specific attachments by ID
  • Perform both add and remove operations in a single request

    Attachment Management: This endpoint was recently enhanced to support full attachment management via JSON API. You can now:

  • Add multiple new attachments using multipart/form-data or file upload
  • Remove specific attachments by providing their IDs
  • Combine both operations in a single update request

    Status Transitions: When a ticket is assigned for the first time (or reassignment occurs) and its status is “new”, it automatically transitions to “open” status.

Authorization required

Authorization header for API access. Supports multiple authentication methods:

  1. Anonymous access: FormUser anonymous - for public operations
  2. Token-based access: FormUser tkn-{token} - for authenticated operations with legacy tokens
  3. Token with Email: FormUser tkn-{token},email:{email} - creates/links virtual user by email
  4. Token with Discord ID: FormUser tkn-{token},discord_id:{discord_id} - creates/links virtual user by Discord ID
  5. Token with JWT: FormUser tkn-{token},{jwt_token} - user identification with JWT token (legacy)
  6. Personal Access Tokens: Bearer YOUR_TOKEN_HERE - recommended for API integrations

Virtual User Creation

When using email: or discord_id: formats with FormUser tokens, the system automatically creates or reuses virtual users. Virtual users are accounts created on-the-fly for form submissions without requiring full user registration. This is useful for:

  • Linking form submissions to specific individuals by email or Discord ID
  • Tracking submissions across multiple reports from the same person
  • Creating user profiles without sign-up workflows

Virtual users created this way are marked as virtual accounts and work across Issues, Feature Requests, and Support Tickets.

Validation Rules:

  • email: format must match RFC 5322 email format. Invalid emails will fall back to anonymous access.
  • discord_id: format must be numeric (digits only). Invalid discord_ids will fall back to anonymous access.
  • Invalid identifiers do not cause HTTP errors; they fall back to anonymous authentication for graceful degradation.

Personal Access Tokens

Personal Access Tokens provide enhanced security and can be created and managed in your account settings. They are ideal for API integrations, automated scripts, and CI/CD pipelines. Tokens can have different permissions, including:

  • can_create_bug_report: Allows creating bug reports
  • can_create_feature_request: Allows creating feature requests
  • can_read_release_list: Allows listing releases
  • can_create_release: Allows creating new releases dynamically via release_label
  • can_update_issue: Allows updating existing issues
  • can_list_issues: Allows listing project issues For more information about Personal Access Tokens, see: https://betahub.io/docs/account/#personal-access-tokens
Path Parameters
Name Type Description
project_id required string
id required string The ticket ID. Can be a numeric ID or scoped ID format.
Header Parameters
Name Type Description
BetaHub-Project-ID required string BetaHub project ID, the same as the project_id
Request Body
multipart/form-data
  • ticket[title] string optional Updated title
  • ticket[description] string optional Updated description
  • ticket[status] string optional Updated status
    new open pending solved closed
  • ticket[priority] string optional Updated priority
    low medium high critical
  • ticket[assigned_to_id] string optional ID of user to assign the ticket to
  • ticket[attachments][] array[string] optional New file attachments to add. Can be provided multiple times for multiple files.
  • ticket[remove_attachment_ids][] array[string] optional IDs of existing attachments to remove. Can be provided multiple times for multiple IDs.
cURL
curl \
  -X PATCH \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "BetaHub-Project-ID: 123" \
  -F "ticket[title]=Example title" \
  -F "ticket[description]=Example description" \
  -F "ticket[status]=new" \
  -F "ticket[priority]=low" \
  "https://app.betahub.io/projects/123/tickets/123.json"
Ruby
require "net/http"
require "json"

uri = URI("https://app.betahub.io/projects/123/tickets/123.json")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Patch.new(uri)
request["Authorization"] = "Bearer YOUR_API_TOKEN"
request["BetaHub-Project-ID"] = "123"

response = http.request(request)
puts response.body
Python
import requests

response = requests.patch(
    "https://app.betahub.io/projects/123/tickets/123.json",
    headers={"Authorization": "Bearer YOUR_API_TOKEN", "BetaHub-Project-ID": "123"}
)
print(response.json())
JavaScript
const response = await fetch("https://app.betahub.io/projects/123/tickets/123.json", {
  method: "PATCH",
  headers: {
    "Authorization": "Bearer YOUR_API_TOKEN",
    "BetaHub-Project-ID": "123"
  }
});
const data = await response.json();
Java
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://app.betahub.io/projects/123/tickets/123.json"))
    .header("Authorization", "Bearer YOUR_API_TOKEN")
    .header("BetaHub-Project-ID", "123")
    .header("Content-Type", "application/json")
    .PATCH(HttpRequest.BodyPublishers.ofString("{\"ticket[title]\":\"string\",\"ticket[description]\":\"string\",\"ticket[status]\":\"new\",\"ticket[priority]\":\"low\",\"ticket[assigned_to_id]\":\"string\",\"ticket[attachments][]\":[\"string\"],\"ticket[remove_attachment_ids][]\":[\"string\"]}"))
    .build();
HttpResponse<String> response = client.send(
    request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
Request Body
{
  "ticket[title]": "string",
  "ticket[description]": "string",
  "ticket[status]": "new",
  "ticket[priority]": "low",
  "ticket[assigned_to_id]": "string",
  "ticket[attachments][]": [
    "string"
  ],
  "ticket[remove_attachment_ids][]": [
    "string"
  ]
}
Responses
application/json
{
  "ticket[status]": "solved",
  "ticket[description]": "Issue resolved - password reset email sent"
}
application/json
{
  "error": "Description can't be blank"
}
application/json
{
  "error": "string",
  "status": "string"
}
application/json
{
  "error": "string",
  "status": "string"
}

Releases

Retrieves a list of releases for the specified project, ordered by creation date (oldest first by default). Returns release details including label, description, download links, and metadata. By default, only published releases are returned. Use the show_drafts parameter (developers only) to include draft releases, or show_archived to include archived releases.
Authorization required

Authorization header for API access. Supports multiple authentication methods:

  1. Anonymous access: FormUser anonymous - for public operations
  2. Token-based access: FormUser tkn-{token} - for authenticated operations with legacy tokens
  3. Token with Email: FormUser tkn-{token},email:{email} - creates/links virtual user by email
  4. Token with Discord ID: FormUser tkn-{token},discord_id:{discord_id} - creates/links virtual user by Discord ID
  5. Token with JWT: FormUser tkn-{token},{jwt_token} - user identification with JWT token (legacy)
  6. Personal Access Tokens: Bearer YOUR_TOKEN_HERE - recommended for API integrations

Virtual User Creation

When using email: or discord_id: formats with FormUser tokens, the system automatically creates or reuses virtual users. Virtual users are accounts created on-the-fly for form submissions without requiring full user registration. This is useful for:

  • Linking form submissions to specific individuals by email or Discord ID
  • Tracking submissions across multiple reports from the same person
  • Creating user profiles without sign-up workflows

Virtual users created this way are marked as virtual accounts and work across Issues, Feature Requests, and Support Tickets.

Validation Rules:

  • email: format must match RFC 5322 email format. Invalid emails will fall back to anonymous access.
  • discord_id: format must be numeric (digits only). Invalid discord_ids will fall back to anonymous access.
  • Invalid identifiers do not cause HTTP errors; they fall back to anonymous authentication for graceful degradation.

Personal Access Tokens

Personal Access Tokens provide enhanced security and can be created and managed in your account settings. They are ideal for API integrations, automated scripts, and CI/CD pipelines. Tokens can have different permissions, including:

  • can_create_bug_report: Allows creating bug reports
  • can_create_feature_request: Allows creating feature requests
  • can_read_release_list: Allows listing releases
  • can_create_release: Allows creating new releases dynamically via release_label
  • can_update_issue: Allows updating existing issues
  • can_list_issues: Allows listing project issues For more information about Personal Access Tokens, see: https://betahub.io/docs/account/#personal-access-tokens
Path Parameters
Name Type Description
project_id required string
Query Parameters
Name Type Description
sort optional string Sort order by creation date. asc for oldest first (default), desc for newest first.
asc desc
Default: asc
show_drafts optional string Include draft releases in the response. Only project developers can view drafts. Set to true to show draft releases. This parameter is ignored for non-developers.
true false
Default: false
show_archived optional string Include archived releases in the response. Set to true to show archived releases.
true false
Default: false
Header Parameters
Name Type Description
BetaHub-Project-ID required string BetaHub project ID, the same as the project_id
cURL
curl \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "BetaHub-Project-ID: 123" \
  "https://app.betahub.io/projects/123/releases.json?sort=asc&show_drafts=false&show_archived=false"
Ruby
require "net/http"

uri = URI("https://app.betahub.io/projects/123/releases.json?sort=asc&show_drafts=false&show_archived=false")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Get.new(uri)
request["Authorization"] = "Bearer YOUR_API_TOKEN"
request["BetaHub-Project-ID"] = "123"

response = http.request(request)
puts response.body
Python
import requests

response = requests.get(
    "https://app.betahub.io/projects/123/releases.json?sort=asc&show_drafts=false&show_archived=false",
    headers={"Authorization": "Bearer YOUR_API_TOKEN", "BetaHub-Project-ID": "123"}
)
print(response.json())
JavaScript
const response = await fetch("https://app.betahub.io/projects/123/releases.json?sort=asc&show_drafts=false&show_archived=false", {
  headers: {
    "Authorization": "Bearer YOUR_API_TOKEN",
    "BetaHub-Project-ID": "123"
  }
});
const data = await response.json();
Java
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://app.betahub.io/projects/123/releases.json?sort=asc&show_drafts=false&show_archived=false"))
    .header("Authorization", "Bearer YOUR_API_TOKEN")
    .header("BetaHub-Project-ID", "123")
    .GET()
    .build();
HttpResponse<String> response = client.send(
    request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
Responses
application/json
[
  {
    "id": "rel-123abc",
    "label": "v1.0.0",
    "summary": "Initial release",
    "description": "First stable version of our game",
    "status": "published",
    "active": true,
    "release_type": "regular",
    "created_at": "2024-10-03T12:34:56Z",
    "updated_at": "2024-10-03T12:34:56Z",
    "download_links": [
      {
        "platform": "windows",
        "url": "https://example.com/download/game-v1.0.0-windows.zip"
      },
      {
        "platform": "macos",
        "url": "https://example.com/download/game-v1.0.0-macos.dmg"
      }
    ],
    "attachments_count": 2,
    "url": "https://app.betahub.io/projects/1/releases/rel-123abc"
  }
]
application/json
{
  "error": "string",
  "status": "string"
}
application/json
{
  "error": "string",
  "status": "string"
}
Creates a new release for a project. Releases contain download links, attachments, and metadata about a version of the project. By default, releases are created as published and trigger notifications to project members. Use release[status]=draft to create a draft release that can be edited before publishing.
Authorization required

Authorization header for API access. Supports multiple authentication methods:

  1. Anonymous access: FormUser anonymous - for public operations
  2. Token-based access: FormUser tkn-{token} - for authenticated operations with legacy tokens
  3. Token with Email: FormUser tkn-{token},email:{email} - creates/links virtual user by email
  4. Token with Discord ID: FormUser tkn-{token},discord_id:{discord_id} - creates/links virtual user by Discord ID
  5. Token with JWT: FormUser tkn-{token},{jwt_token} - user identification with JWT token (legacy)
  6. Personal Access Tokens: Bearer YOUR_TOKEN_HERE - recommended for API integrations

Virtual User Creation

When using email: or discord_id: formats with FormUser tokens, the system automatically creates or reuses virtual users. Virtual users are accounts created on-the-fly for form submissions without requiring full user registration. This is useful for:

  • Linking form submissions to specific individuals by email or Discord ID
  • Tracking submissions across multiple reports from the same person
  • Creating user profiles without sign-up workflows

Virtual users created this way are marked as virtual accounts and work across Issues, Feature Requests, and Support Tickets.

Validation Rules:

  • email: format must match RFC 5322 email format. Invalid emails will fall back to anonymous access.
  • discord_id: format must be numeric (digits only). Invalid discord_ids will fall back to anonymous access.
  • Invalid identifiers do not cause HTTP errors; they fall back to anonymous authentication for graceful degradation.

Personal Access Tokens

Personal Access Tokens provide enhanced security and can be created and managed in your account settings. They are ideal for API integrations, automated scripts, and CI/CD pipelines. Tokens can have different permissions, including:

  • can_create_bug_report: Allows creating bug reports
  • can_create_feature_request: Allows creating feature requests
  • can_read_release_list: Allows listing releases
  • can_create_release: Allows creating new releases dynamically via release_label
  • can_update_issue: Allows updating existing issues
  • can_list_issues: Allows listing project issues For more information about Personal Access Tokens, see: https://betahub.io/docs/account/#personal-access-tokens
Path Parameters
Name Type Description
project_id required string
Header Parameters
Name Type Description
BetaHub-Project-ID required string BetaHub project ID, the same as the project_id
Request Body
multipart/form-data
  • release[label] string required Version label for the release (e.g., “v1.0.0”)
  • release[summary] string optional Brief summary of the release
  • release[description] string optional Detailed description of the release changes
  • release[send_images_separately] boolean optional Whether to send attachment images separately in notifications
  • release[attachments] array[string] optional File attachments for the release
  • release[download_links_attributes] array[object] optional
    • platform string optional Platform name (e.g., “windows”, “macos”, “linux”)
    • url string optional Download URL for this platform
    • link_enabled boolean optional Whether this download link is enabled
  • release[status] string optional The publication status for the release. Set to draft to create a draft release that is only visible to developers and does not trigger notifications. Set to published (default) to publish immediately and notify project members.
    draft published
cURL
curl \
  -X POST \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "BetaHub-Project-ID: 123" \
  -F "release[label]=string" \
  -F "release[summary]=string" \
  -F "release[description]=Example description" \
  -F "release[send_images_separately]=true" \
  "https://app.betahub.io/projects/123/releases.json"
Ruby
require "net/http"
require "json"

uri = URI("https://app.betahub.io/projects/123/releases.json")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Post.new(uri)
request["Authorization"] = "Bearer YOUR_API_TOKEN"
request["BetaHub-Project-ID"] = "123"

response = http.request(request)
puts response.body
Python
import requests

response = requests.post(
    "https://app.betahub.io/projects/123/releases.json",
    headers={"Authorization": "Bearer YOUR_API_TOKEN", "BetaHub-Project-ID": "123"}
)
print(response.json())
JavaScript
const response = await fetch("https://app.betahub.io/projects/123/releases.json", {
  method: "POST",
  headers: {
    "Authorization": "Bearer YOUR_API_TOKEN",
    "BetaHub-Project-ID": "123"
  }
});
const data = await response.json();
Java
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://app.betahub.io/projects/123/releases.json"))
    .header("Authorization", "Bearer YOUR_API_TOKEN")
    .header("BetaHub-Project-ID", "123")
    .header("Content-Type", "application/json")
    .POST(HttpRequest.BodyPublishers.ofString("{\"release[label]\":\"string\",\"release[summary]\":\"string\",\"release[description]\":\"string\",\"release[send_images_separately]\":true,\"release[attachments]\":[\"string\"],\"release[download_links_attributes]\":[{\"platform\":\"string\",\"url\":\"https://example.com\",\"link_enabled\":true}],\"release[status]\":\"draft\"}"))
    .build();
HttpResponse<String> response = client.send(
    request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
Request Body
{
  "release[label]": "string",
  "release[summary]": "string",
  "release[description]": "string",
  "release[send_images_separately]": true,
  "release[attachments]": [
    "string"
  ],
  "release[download_links_attributes]": [
    {
      "platform": "string",
      "url": "https://example.com",
      "link_enabled": true
    }
  ],
  "release[status]": "draft"
}
Responses
application/json
{
  "release[label]": "v1.1.0",
  "release[summary]": "Bug fixes and improvements",
  "release[description]": "This release includes several bug fixes and performance improvements.",
  "release[download_links_attributes]": [
    {
      "platform": "windows",
      "url": "https://example.com/download/game-v1.1.0-windows.zip",
      "link_enabled": true
    }
  ]
}
application/json
{
  "error": "string",
  "status": "string"
}
application/json
{
  "error": "string",
  "status": "string"
}
Retrieves detailed information about a specific release, including all download links, attachments, and metadata. Draft releases are only visible to project developers.
Authorization required

Authorization header for API access. Supports multiple authentication methods:

  1. Anonymous access: FormUser anonymous - for public operations
  2. Token-based access: FormUser tkn-{token} - for authenticated operations with legacy tokens
  3. Token with Email: FormUser tkn-{token},email:{email} - creates/links virtual user by email
  4. Token with Discord ID: FormUser tkn-{token},discord_id:{discord_id} - creates/links virtual user by Discord ID
  5. Token with JWT: FormUser tkn-{token},{jwt_token} - user identification with JWT token (legacy)
  6. Personal Access Tokens: Bearer YOUR_TOKEN_HERE - recommended for API integrations

Virtual User Creation

When using email: or discord_id: formats with FormUser tokens, the system automatically creates or reuses virtual users. Virtual users are accounts created on-the-fly for form submissions without requiring full user registration. This is useful for:

  • Linking form submissions to specific individuals by email or Discord ID
  • Tracking submissions across multiple reports from the same person
  • Creating user profiles without sign-up workflows

Virtual users created this way are marked as virtual accounts and work across Issues, Feature Requests, and Support Tickets.

Validation Rules:

  • email: format must match RFC 5322 email format. Invalid emails will fall back to anonymous access.
  • discord_id: format must be numeric (digits only). Invalid discord_ids will fall back to anonymous access.
  • Invalid identifiers do not cause HTTP errors; they fall back to anonymous authentication for graceful degradation.

Personal Access Tokens

Personal Access Tokens provide enhanced security and can be created and managed in your account settings. They are ideal for API integrations, automated scripts, and CI/CD pipelines. Tokens can have different permissions, including:

  • can_create_bug_report: Allows creating bug reports
  • can_create_feature_request: Allows creating feature requests
  • can_read_release_list: Allows listing releases
  • can_create_release: Allows creating new releases dynamically via release_label
  • can_update_issue: Allows updating existing issues
  • can_list_issues: Allows listing project issues For more information about Personal Access Tokens, see: https://betahub.io/docs/account/#personal-access-tokens
Path Parameters
Name Type Description
project_id required string
release_id required string
Header Parameters
Name Type Description
BetaHub-Project-ID required string BetaHub project ID, the same as the project_id
cURL
curl \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "BetaHub-Project-ID: 123" \
  "https://app.betahub.io/projects/123/releases/123.json"
Ruby
require "net/http"

uri = URI("https://app.betahub.io/projects/123/releases/123.json")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Get.new(uri)
request["Authorization"] = "Bearer YOUR_API_TOKEN"
request["BetaHub-Project-ID"] = "123"

response = http.request(request)
puts response.body
Python
import requests

response = requests.get(
    "https://app.betahub.io/projects/123/releases/123.json",
    headers={"Authorization": "Bearer YOUR_API_TOKEN", "BetaHub-Project-ID": "123"}
)
print(response.json())
JavaScript
const response = await fetch("https://app.betahub.io/projects/123/releases/123.json", {
  headers: {
    "Authorization": "Bearer YOUR_API_TOKEN",
    "BetaHub-Project-ID": "123"
  }
});
const data = await response.json();
Java
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://app.betahub.io/projects/123/releases/123.json"))
    .header("Authorization", "Bearer YOUR_API_TOKEN")
    .header("BetaHub-Project-ID", "123")
    .GET()
    .build();
HttpResponse<String> response = client.send(
    request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
Responses
application/json
{
  "id": "rel-123abc",
  "label": "v1.0.0",
  "summary": "Initial release",
  "description": "First stable version of our game",
  "status": "published",
  "active": true,
  "release_type": "regular",
  "created_at": "2024-10-03T12:34:56Z",
  "updated_at": "2024-10-03T12:34:56Z",
  "download_links": [
    {
      "platform": "windows",
      "url": "https://example.com/download/game-v1.0.0-windows.zip"
    },
    {
      "platform": "macos",
      "url": "https://example.com/download/game-v1.0.0-macos.dmg"
    }
  ],
  "attachments_count": 2,
  "url": "https://app.betahub.io/projects/1/releases/rel-123abc"
}
application/json
{
  "error": "string",
  "status": "string"
}
application/json
{
  "error": "string",
  "status": "string"
}
Updates an existing release with new information. Download links and attachments are handled separately from the main release data.
Authorization required

Authorization header for API access. Supports multiple authentication methods:

  1. Anonymous access: FormUser anonymous - for public operations
  2. Token-based access: FormUser tkn-{token} - for authenticated operations with legacy tokens
  3. Token with Email: FormUser tkn-{token},email:{email} - creates/links virtual user by email
  4. Token with Discord ID: FormUser tkn-{token},discord_id:{discord_id} - creates/links virtual user by Discord ID
  5. Token with JWT: FormUser tkn-{token},{jwt_token} - user identification with JWT token (legacy)
  6. Personal Access Tokens: Bearer YOUR_TOKEN_HERE - recommended for API integrations

Virtual User Creation

When using email: or discord_id: formats with FormUser tokens, the system automatically creates or reuses virtual users. Virtual users are accounts created on-the-fly for form submissions without requiring full user registration. This is useful for:

  • Linking form submissions to specific individuals by email or Discord ID
  • Tracking submissions across multiple reports from the same person
  • Creating user profiles without sign-up workflows

Virtual users created this way are marked as virtual accounts and work across Issues, Feature Requests, and Support Tickets.

Validation Rules:

  • email: format must match RFC 5322 email format. Invalid emails will fall back to anonymous access.
  • discord_id: format must be numeric (digits only). Invalid discord_ids will fall back to anonymous access.
  • Invalid identifiers do not cause HTTP errors; they fall back to anonymous authentication for graceful degradation.

Personal Access Tokens

Personal Access Tokens provide enhanced security and can be created and managed in your account settings. They are ideal for API integrations, automated scripts, and CI/CD pipelines. Tokens can have different permissions, including:

  • can_create_bug_report: Allows creating bug reports
  • can_create_feature_request: Allows creating feature requests
  • can_read_release_list: Allows listing releases
  • can_create_release: Allows creating new releases dynamically via release_label
  • can_update_issue: Allows updating existing issues
  • can_list_issues: Allows listing project issues For more information about Personal Access Tokens, see: https://betahub.io/docs/account/#personal-access-tokens
Path Parameters
Name Type Description
project_id required string
release_id required string
Header Parameters
Name Type Description
BetaHub-Project-ID required string BetaHub project ID, the same as the project_id
Request Body
application/json
  • release[label] string optional Updated version label
  • release[summary] string optional Updated summary
  • release[description] string optional Updated description
  • release[send_images_separately] boolean optional Whether to send attachment images separately
  • release[download_links_attributes] array[object] optional
    • id string optional ID of existing download link (for updates)
    • platform string optional Platform name
    • url string optional Download URL
    • link_enabled boolean optional Whether this download link is enabled
  • release[remove_attachments] array[string] optional IDs of attachments to remove
  • release[attachments] array[string] optional New attachments to add
cURL
curl \
  -X PUT \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "BetaHub-Project-ID: 123" \
  -H "Content-Type: application/json" \
  -d '{
  "release[label]": "string",
  "release[summary]": "string",
  "release[description]": "string",
  "release[send_images_separately]": true,
  "release[download_links_attributes]": [
    {
      "id": "https://example.com",
      "platform": "string",
      "url": "https://example.com",
      "link_enabled": true
    }
  ],
  "release[remove_attachments]": [
    "string"
  ],
  "release[attachments]": [
    "string"
  ]
}' \
  "https://app.betahub.io/projects/123/releases/123.json"
Ruby
require "net/http"
require "json"

uri = URI("https://app.betahub.io/projects/123/releases/123.json")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Put.new(uri)
request["Authorization"] = "Bearer YOUR_API_TOKEN"
request["BetaHub-Project-ID"] = "123"
request["Content-Type"] = "application/json"
request.body = {
  "release[label]": "string",
  "release[summary]": "string",
  "release[description]": "string",
  "release[send_images_separately]": true,
  "release[download_links_attributes]": [
    {
      "id": "https://example.com",
      "platform": "string",
      "url": "https://example.com",
      "link_enabled": true
    }
  ],
  "release[remove_attachments]": [
    "string"
  ],
  "release[attachments]": [
    "string"
  ]
}

response = http.request(request)
puts response.body
Python
import requests

response = requests.put(
    "https://app.betahub.io/projects/123/releases/123.json",
    headers={"Authorization": "Bearer YOUR_API_TOKEN", "BetaHub-Project-ID": "123"},
    json={
      "release[label]": "string",
      "release[summary]": "string",
      "release[description]": "string",
      "release[send_images_separately]": true,
      "release[download_links_attributes]": [
        {
          "id": "https://example.com",
          "platform": "string",
          "url": "https://example.com",
          "link_enabled": true
        }
      ],
      "release[remove_attachments]": [
        "string"
      ],
      "release[attachments]": [
        "string"
      ]
    }
)
print(response.json())
JavaScript
const response = await fetch("https://app.betahub.io/projects/123/releases/123.json", {
  method: "PUT",
  headers: {
    "Authorization": "Bearer YOUR_API_TOKEN",
    "BetaHub-Project-ID": "123",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    "release[label]": "string",
    "release[summary]": "string",
    "release[description]": "string",
    "release[send_images_separately]": true,
    "release[download_links_attributes]": [
      {
        "id": "https://example.com",
        "platform": "string",
        "url": "https://example.com",
        "link_enabled": true
      }
    ],
    "release[remove_attachments]": [
      "string"
    ],
    "release[attachments]": [
      "string"
    ]
  })
});
const data = await response.json();
Java
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://app.betahub.io/projects/123/releases/123.json"))
    .header("Authorization", "Bearer YOUR_API_TOKEN")
    .header("BetaHub-Project-ID", "123")
    .header("Content-Type", "application/json")
    .PUT(HttpRequest.BodyPublishers.ofString("{\"release[label]\":\"string\",\"release[summary]\":\"string\",\"release[description]\":\"string\",\"release[send_images_separately]\":true,\"release[download_links_attributes]\":[{\"id\":\"https://example.com\",\"platform\":\"string\",\"url\":\"https://example.com\",\"link_enabled\":true}],\"release[remove_attachments]\":[\"string\"],\"release[attachments]\":[\"string\"]}"))
    .build();
HttpResponse<String> response = client.send(
    request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
Request Body
{
  "release[label]": "string",
  "release[summary]": "string",
  "release[description]": "string",
  "release[send_images_separately]": true,
  "release[download_links_attributes]": [
    {
      "id": "https://example.com",
      "platform": "string",
      "url": "https://example.com",
      "link_enabled": true
    }
  ],
  "release[remove_attachments]": [
    "string"
  ],
  "release[attachments]": [
    "string"
  ]
}
Responses
application/json
{
  "release[label]": "v1.0.1",
  "release[summary]": "Hotfix release",
  "release[description]": "Critical bug fixes for v1.0.0"
}
application/json
{
  "error": "string",
  "status": "string"
}
application/json
{
  "error": "string",
  "status": "string"
}
application/json
{
  "error": "string",
  "status": "string"
}
Deletes a release from the project. Cannot delete the only published release of a project - archive it instead. Cannot delete a release that has issues assigned. All associated download links and attachments are also removed.
Authorization required

Authorization header for API access. Supports multiple authentication methods:

  1. Anonymous access: FormUser anonymous - for public operations
  2. Token-based access: FormUser tkn-{token} - for authenticated operations with legacy tokens
  3. Token with Email: FormUser tkn-{token},email:{email} - creates/links virtual user by email
  4. Token with Discord ID: FormUser tkn-{token},discord_id:{discord_id} - creates/links virtual user by Discord ID
  5. Token with JWT: FormUser tkn-{token},{jwt_token} - user identification with JWT token (legacy)
  6. Personal Access Tokens: Bearer YOUR_TOKEN_HERE - recommended for API integrations

Virtual User Creation

When using email: or discord_id: formats with FormUser tokens, the system automatically creates or reuses virtual users. Virtual users are accounts created on-the-fly for form submissions without requiring full user registration. This is useful for:

  • Linking form submissions to specific individuals by email or Discord ID
  • Tracking submissions across multiple reports from the same person
  • Creating user profiles without sign-up workflows

Virtual users created this way are marked as virtual accounts and work across Issues, Feature Requests, and Support Tickets.

Validation Rules:

  • email: format must match RFC 5322 email format. Invalid emails will fall back to anonymous access.
  • discord_id: format must be numeric (digits only). Invalid discord_ids will fall back to anonymous access.
  • Invalid identifiers do not cause HTTP errors; they fall back to anonymous authentication for graceful degradation.

Personal Access Tokens

Personal Access Tokens provide enhanced security and can be created and managed in your account settings. They are ideal for API integrations, automated scripts, and CI/CD pipelines. Tokens can have different permissions, including:

  • can_create_bug_report: Allows creating bug reports
  • can_create_feature_request: Allows creating feature requests
  • can_read_release_list: Allows listing releases
  • can_create_release: Allows creating new releases dynamically via release_label
  • can_update_issue: Allows updating existing issues
  • can_list_issues: Allows listing project issues For more information about Personal Access Tokens, see: https://betahub.io/docs/account/#personal-access-tokens
Path Parameters
Name Type Description
project_id required string
release_id required string
Header Parameters
Name Type Description
BetaHub-Project-ID required string BetaHub project ID, the same as the project_id
cURL
curl \
  -X DELETE \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "BetaHub-Project-ID: 123" \
  "https://app.betahub.io/projects/123/releases/123.json"
Ruby
require "net/http"

uri = URI("https://app.betahub.io/projects/123/releases/123.json")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Delete.new(uri)
request["Authorization"] = "Bearer YOUR_API_TOKEN"
request["BetaHub-Project-ID"] = "123"

response = http.request(request)
puts response.body
Python
import requests

response = requests.delete(
    "https://app.betahub.io/projects/123/releases/123.json",
    headers={"Authorization": "Bearer YOUR_API_TOKEN", "BetaHub-Project-ID": "123"}
)
print(response.json())
JavaScript
const response = await fetch("https://app.betahub.io/projects/123/releases/123.json", {
  method: "DELETE",
  headers: {
    "Authorization": "Bearer YOUR_API_TOKEN",
    "BetaHub-Project-ID": "123"
  }
});
const data = await response.json();
Java
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://app.betahub.io/projects/123/releases/123.json"))
    .header("Authorization", "Bearer YOUR_API_TOKEN")
    .header("BetaHub-Project-ID", "123")
    .method("DELETE", HttpRequest.BodyPublishers.noBody())
    .build();
HttpResponse<String> response = client.send(
    request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
Responses
application/json
{
  "success": true,
  "message": "Release was successfully deleted."
}
application/json
{
  "error": "Cannot delete the only published release for this project. Archive it instead."
}
application/json
{
  "error": "string",
  "status": "string"
}
application/json
{
  "error": "string",
  "status": "string"
}
Provides download information for a release. If a platform parameter is provided, tracks the download and redirects to the actual download URL. Otherwise, returns download information for all available platforms.
Authorization required

Authorization header for API access. Supports multiple authentication methods:

  1. Anonymous access: FormUser anonymous - for public operations
  2. Token-based access: FormUser tkn-{token} - for authenticated operations with legacy tokens
  3. Token with Email: FormUser tkn-{token},email:{email} - creates/links virtual user by email
  4. Token with Discord ID: FormUser tkn-{token},discord_id:{discord_id} - creates/links virtual user by Discord ID
  5. Token with JWT: FormUser tkn-{token},{jwt_token} - user identification with JWT token (legacy)
  6. Personal Access Tokens: Bearer YOUR_TOKEN_HERE - recommended for API integrations

Virtual User Creation

When using email: or discord_id: formats with FormUser tokens, the system automatically creates or reuses virtual users. Virtual users are accounts created on-the-fly for form submissions without requiring full user registration. This is useful for:

  • Linking form submissions to specific individuals by email or Discord ID
  • Tracking submissions across multiple reports from the same person
  • Creating user profiles without sign-up workflows

Virtual users created this way are marked as virtual accounts and work across Issues, Feature Requests, and Support Tickets.

Validation Rules:

  • email: format must match RFC 5322 email format. Invalid emails will fall back to anonymous access.
  • discord_id: format must be numeric (digits only). Invalid discord_ids will fall back to anonymous access.
  • Invalid identifiers do not cause HTTP errors; they fall back to anonymous authentication for graceful degradation.

Personal Access Tokens

Personal Access Tokens provide enhanced security and can be created and managed in your account settings. They are ideal for API integrations, automated scripts, and CI/CD pipelines. Tokens can have different permissions, including:

  • can_create_bug_report: Allows creating bug reports
  • can_create_feature_request: Allows creating feature requests
  • can_read_release_list: Allows listing releases
  • can_create_release: Allows creating new releases dynamically via release_label
  • can_update_issue: Allows updating existing issues
  • can_list_issues: Allows listing project issues For more information about Personal Access Tokens, see: https://betahub.io/docs/account/#personal-access-tokens
Path Parameters
Name Type Description
project_id required string
release_id required string
Query Parameters
Name Type Description
platform optional string Platform to download (e.g., “windows”, “macos”, “linux”). If provided, redirects to download URL.
Header Parameters
Name Type Description
BetaHub-Project-ID required string BetaHub project ID, the same as the project_id
cURL
curl \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "BetaHub-Project-ID: 123" \
  "https://app.betahub.io/projects/123/releases/123/download?platform=example"
Ruby
require "net/http"

uri = URI("https://app.betahub.io/projects/123/releases/123/download?platform=example")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Get.new(uri)
request["Authorization"] = "Bearer YOUR_API_TOKEN"
request["BetaHub-Project-ID"] = "123"

response = http.request(request)
puts response.body
Python
import requests

response = requests.get(
    "https://app.betahub.io/projects/123/releases/123/download?platform=example",
    headers={"Authorization": "Bearer YOUR_API_TOKEN", "BetaHub-Project-ID": "123"}
)
print(response.json())
JavaScript
const response = await fetch("https://app.betahub.io/projects/123/releases/123/download?platform=example", {
  headers: {
    "Authorization": "Bearer YOUR_API_TOKEN",
    "BetaHub-Project-ID": "123"
  }
});
const data = await response.json();
Java
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://app.betahub.io/projects/123/releases/123/download?platform=example"))
    .header("Authorization", "Bearer YOUR_API_TOKEN")
    .header("BetaHub-Project-ID", "123")
    .GET()
    .build();
HttpResponse<String> response = client.send(
    request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
Responses
application/json
{
  "available_platforms": [
    {
      "platform": "windows",
      "download_url": "https://app.betahub.io/projects/1/releases/rel-123abc/download?platform=windows",
      "download_count": 42
    },
    {
      "platform": "macos",
      "download_url": "https://app.betahub.io/projects/1/releases/rel-123abc/download?platform=macos",
      "download_count": 18
    }
  ]
}
Redirect to actual download URL (when platform specified)
application/json
{
  "error": "string",
  "status": "string"
}
application/json
{
  "error": "string",
  "status": "string"
}
Publishes a draft release, making it visible to all project members and sending notifications. This is an idempotent operation - calling it on an already published release returns success without changes.
Authorization required

Authorization header for API access. Supports multiple authentication methods:

  1. Anonymous access: FormUser anonymous - for public operations
  2. Token-based access: FormUser tkn-{token} - for authenticated operations with legacy tokens
  3. Token with Email: FormUser tkn-{token},email:{email} - creates/links virtual user by email
  4. Token with Discord ID: FormUser tkn-{token},discord_id:{discord_id} - creates/links virtual user by Discord ID
  5. Token with JWT: FormUser tkn-{token},{jwt_token} - user identification with JWT token (legacy)
  6. Personal Access Tokens: Bearer YOUR_TOKEN_HERE - recommended for API integrations

Virtual User Creation

When using email: or discord_id: formats with FormUser tokens, the system automatically creates or reuses virtual users. Virtual users are accounts created on-the-fly for form submissions without requiring full user registration. This is useful for:

  • Linking form submissions to specific individuals by email or Discord ID
  • Tracking submissions across multiple reports from the same person
  • Creating user profiles without sign-up workflows

Virtual users created this way are marked as virtual accounts and work across Issues, Feature Requests, and Support Tickets.

Validation Rules:

  • email: format must match RFC 5322 email format. Invalid emails will fall back to anonymous access.
  • discord_id: format must be numeric (digits only). Invalid discord_ids will fall back to anonymous access.
  • Invalid identifiers do not cause HTTP errors; they fall back to anonymous authentication for graceful degradation.

Personal Access Tokens

Personal Access Tokens provide enhanced security and can be created and managed in your account settings. They are ideal for API integrations, automated scripts, and CI/CD pipelines. Tokens can have different permissions, including:

  • can_create_bug_report: Allows creating bug reports
  • can_create_feature_request: Allows creating feature requests
  • can_read_release_list: Allows listing releases
  • can_create_release: Allows creating new releases dynamically via release_label
  • can_update_issue: Allows updating existing issues
  • can_list_issues: Allows listing project issues For more information about Personal Access Tokens, see: https://betahub.io/docs/account/#personal-access-tokens
Path Parameters
Name Type Description
project_id required string
release_id required string
Header Parameters
Name Type Description
BetaHub-Project-ID required string BetaHub project ID, the same as the project_id
cURL
curl \
  -X POST \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "BetaHub-Project-ID: 123" \
  "https://app.betahub.io/projects/123/releases/123/publish.json"
Ruby
require "net/http"

uri = URI("https://app.betahub.io/projects/123/releases/123/publish.json")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Post.new(uri)
request["Authorization"] = "Bearer YOUR_API_TOKEN"
request["BetaHub-Project-ID"] = "123"

response = http.request(request)
puts response.body
Python
import requests

response = requests.post(
    "https://app.betahub.io/projects/123/releases/123/publish.json",
    headers={"Authorization": "Bearer YOUR_API_TOKEN", "BetaHub-Project-ID": "123"}
)
print(response.json())
JavaScript
const response = await fetch("https://app.betahub.io/projects/123/releases/123/publish.json", {
  method: "POST",
  headers: {
    "Authorization": "Bearer YOUR_API_TOKEN",
    "BetaHub-Project-ID": "123"
  }
});
const data = await response.json();
Java
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://app.betahub.io/projects/123/releases/123/publish.json"))
    .header("Authorization", "Bearer YOUR_API_TOKEN")
    .header("BetaHub-Project-ID", "123")
    .method("POST", HttpRequest.BodyPublishers.noBody())
    .build();
HttpResponse<String> response = client.send(
    request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
Responses
application/json
{
  "id": "rel-123abc",
  "label": "v1.0.0",
  "summary": "Initial release",
  "description": "First stable version",
  "status": "published",
  "active": true,
  "release_type": "regular",
  "created_at": "2024-10-03T12:34:56Z",
  "updated_at": "2024-10-03T15:20:30Z",
  "download_links": [],
  "attachments_count": 0,
  "url": "https://app.betahub.io/projects/1/releases/rel-123abc"
}
application/json
{
  "error": "string",
  "status": "string"
}
application/json
{
  "error": "string",
  "status": "string"
}
Archives a release, hiding it from testers and release selection forms. Cannot archive the only published release - at least one published release must remain. Use /restore to bring an archived release back.
Authorization required

Authorization header for API access. Supports multiple authentication methods:

  1. Anonymous access: FormUser anonymous - for public operations
  2. Token-based access: FormUser tkn-{token} - for authenticated operations with legacy tokens
  3. Token with Email: FormUser tkn-{token},email:{email} - creates/links virtual user by email
  4. Token with Discord ID: FormUser tkn-{token},discord_id:{discord_id} - creates/links virtual user by Discord ID
  5. Token with JWT: FormUser tkn-{token},{jwt_token} - user identification with JWT token (legacy)
  6. Personal Access Tokens: Bearer YOUR_TOKEN_HERE - recommended for API integrations

Virtual User Creation

When using email: or discord_id: formats with FormUser tokens, the system automatically creates or reuses virtual users. Virtual users are accounts created on-the-fly for form submissions without requiring full user registration. This is useful for:

  • Linking form submissions to specific individuals by email or Discord ID
  • Tracking submissions across multiple reports from the same person
  • Creating user profiles without sign-up workflows

Virtual users created this way are marked as virtual accounts and work across Issues, Feature Requests, and Support Tickets.

Validation Rules:

  • email: format must match RFC 5322 email format. Invalid emails will fall back to anonymous access.
  • discord_id: format must be numeric (digits only). Invalid discord_ids will fall back to anonymous access.
  • Invalid identifiers do not cause HTTP errors; they fall back to anonymous authentication for graceful degradation.

Personal Access Tokens

Personal Access Tokens provide enhanced security and can be created and managed in your account settings. They are ideal for API integrations, automated scripts, and CI/CD pipelines. Tokens can have different permissions, including:

  • can_create_bug_report: Allows creating bug reports
  • can_create_feature_request: Allows creating feature requests
  • can_read_release_list: Allows listing releases
  • can_create_release: Allows creating new releases dynamically via release_label
  • can_update_issue: Allows updating existing issues
  • can_list_issues: Allows listing project issues For more information about Personal Access Tokens, see: https://betahub.io/docs/account/#personal-access-tokens
Path Parameters
Name Type Description
project_id required string
release_id required string
Header Parameters
Name Type Description
BetaHub-Project-ID required string BetaHub project ID, the same as the project_id
cURL
curl \
  -X POST \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "BetaHub-Project-ID: 123" \
  "https://app.betahub.io/projects/123/releases/123/archive.json"
Ruby
require "net/http"

uri = URI("https://app.betahub.io/projects/123/releases/123/archive.json")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Post.new(uri)
request["Authorization"] = "Bearer YOUR_API_TOKEN"
request["BetaHub-Project-ID"] = "123"

response = http.request(request)
puts response.body
Python
import requests

response = requests.post(
    "https://app.betahub.io/projects/123/releases/123/archive.json",
    headers={"Authorization": "Bearer YOUR_API_TOKEN", "BetaHub-Project-ID": "123"}
)
print(response.json())
JavaScript
const response = await fetch("https://app.betahub.io/projects/123/releases/123/archive.json", {
  method: "POST",
  headers: {
    "Authorization": "Bearer YOUR_API_TOKEN",
    "BetaHub-Project-ID": "123"
  }
});
const data = await response.json();
Java
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://app.betahub.io/projects/123/releases/123/archive.json"))
    .header("Authorization", "Bearer YOUR_API_TOKEN")
    .header("BetaHub-Project-ID", "123")
    .method("POST", HttpRequest.BodyPublishers.noBody())
    .build();
HttpResponse<String> response = client.send(
    request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
Responses
application/json
{
  "id": "rel-123abc",
  "label": "v0.9.0",
  "summary": "Beta release",
  "description": "Old beta version",
  "status": "archived",
  "active": false,
  "release_type": "regular",
  "created_at": "2024-09-01T12:34:56Z",
  "updated_at": "2024-10-03T15:20:30Z",
  "download_links": [],
  "attachments_count": 0,
  "url": "https://app.betahub.io/projects/1/releases/rel-123abc"
}
application/json
{
  "error": "string",
  "status": "string"
}
application/json
{
  "error": "string",
  "status": "string"
}
application/json
{
  "error": "Cannot archive the only published release for this project."
}
Restores an archived release back to published status, making it visible to testers and available in release selection forms again.
Authorization required

Authorization header for API access. Supports multiple authentication methods:

  1. Anonymous access: FormUser anonymous - for public operations
  2. Token-based access: FormUser tkn-{token} - for authenticated operations with legacy tokens
  3. Token with Email: FormUser tkn-{token},email:{email} - creates/links virtual user by email
  4. Token with Discord ID: FormUser tkn-{token},discord_id:{discord_id} - creates/links virtual user by Discord ID
  5. Token with JWT: FormUser tkn-{token},{jwt_token} - user identification with JWT token (legacy)
  6. Personal Access Tokens: Bearer YOUR_TOKEN_HERE - recommended for API integrations

Virtual User Creation

When using email: or discord_id: formats with FormUser tokens, the system automatically creates or reuses virtual users. Virtual users are accounts created on-the-fly for form submissions without requiring full user registration. This is useful for:

  • Linking form submissions to specific individuals by email or Discord ID
  • Tracking submissions across multiple reports from the same person
  • Creating user profiles without sign-up workflows

Virtual users created this way are marked as virtual accounts and work across Issues, Feature Requests, and Support Tickets.

Validation Rules:

  • email: format must match RFC 5322 email format. Invalid emails will fall back to anonymous access.
  • discord_id: format must be numeric (digits only). Invalid discord_ids will fall back to anonymous access.
  • Invalid identifiers do not cause HTTP errors; they fall back to anonymous authentication for graceful degradation.

Personal Access Tokens

Personal Access Tokens provide enhanced security and can be created and managed in your account settings. They are ideal for API integrations, automated scripts, and CI/CD pipelines. Tokens can have different permissions, including:

  • can_create_bug_report: Allows creating bug reports
  • can_create_feature_request: Allows creating feature requests
  • can_read_release_list: Allows listing releases
  • can_create_release: Allows creating new releases dynamically via release_label
  • can_update_issue: Allows updating existing issues
  • can_list_issues: Allows listing project issues For more information about Personal Access Tokens, see: https://betahub.io/docs/account/#personal-access-tokens
Path Parameters
Name Type Description
project_id required string
release_id required string
Header Parameters
Name Type Description
BetaHub-Project-ID required string BetaHub project ID, the same as the project_id
cURL
curl \
  -X POST \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "BetaHub-Project-ID: 123" \
  "https://app.betahub.io/projects/123/releases/123/restore.json"
Ruby
require "net/http"

uri = URI("https://app.betahub.io/projects/123/releases/123/restore.json")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Post.new(uri)
request["Authorization"] = "Bearer YOUR_API_TOKEN"
request["BetaHub-Project-ID"] = "123"

response = http.request(request)
puts response.body
Python
import requests

response = requests.post(
    "https://app.betahub.io/projects/123/releases/123/restore.json",
    headers={"Authorization": "Bearer YOUR_API_TOKEN", "BetaHub-Project-ID": "123"}
)
print(response.json())
JavaScript
const response = await fetch("https://app.betahub.io/projects/123/releases/123/restore.json", {
  method: "POST",
  headers: {
    "Authorization": "Bearer YOUR_API_TOKEN",
    "BetaHub-Project-ID": "123"
  }
});
const data = await response.json();
Java
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://app.betahub.io/projects/123/releases/123/restore.json"))
    .header("Authorization", "Bearer YOUR_API_TOKEN")
    .header("BetaHub-Project-ID", "123")
    .method("POST", HttpRequest.BodyPublishers.noBody())
    .build();
HttpResponse<String> response = client.send(
    request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
Responses
application/json
{
  "id": "rel-123abc",
  "label": "v0.9.0",
  "summary": "Beta release",
  "description": "Old beta version",
  "status": "published",
  "active": true,
  "release_type": "regular",
  "created_at": "2024-09-01T12:34:56Z",
  "updated_at": "2024-10-03T15:20:30Z",
  "download_links": [],
  "attachments_count": 0,
  "url": "https://app.betahub.io/projects/1/releases/rel-123abc"
}
application/json
{
  "error": "string",
  "status": "string"
}
application/json
{
  "error": "string",
  "status": "string"
}
application/json
{
  "error": "string",
  "status": "string"
}

Game Facts

Retrieves comprehensive game facts data for a project in JSON format. Game facts include information about the game’s mechanics, technical specifications, target audience, platforms, glossary terms, and other project-specific details that help with AI-powered issue categorization and context understanding.
Authorization required

Authorization header for API access. Supports multiple authentication methods:

  1. Anonymous access: FormUser anonymous - for public operations
  2. Token-based access: FormUser tkn-{token} - for authenticated operations with legacy tokens
  3. Token with Email: FormUser tkn-{token},email:{email} - creates/links virtual user by email
  4. Token with Discord ID: FormUser tkn-{token},discord_id:{discord_id} - creates/links virtual user by Discord ID
  5. Token with JWT: FormUser tkn-{token},{jwt_token} - user identification with JWT token (legacy)
  6. Personal Access Tokens: Bearer YOUR_TOKEN_HERE - recommended for API integrations

Virtual User Creation

When using email: or discord_id: formats with FormUser tokens, the system automatically creates or reuses virtual users. Virtual users are accounts created on-the-fly for form submissions without requiring full user registration. This is useful for:

  • Linking form submissions to specific individuals by email or Discord ID
  • Tracking submissions across multiple reports from the same person
  • Creating user profiles without sign-up workflows

Virtual users created this way are marked as virtual accounts and work across Issues, Feature Requests, and Support Tickets.

Validation Rules:

  • email: format must match RFC 5322 email format. Invalid emails will fall back to anonymous access.
  • discord_id: format must be numeric (digits only). Invalid discord_ids will fall back to anonymous access.
  • Invalid identifiers do not cause HTTP errors; they fall back to anonymous authentication for graceful degradation.

Personal Access Tokens

Personal Access Tokens provide enhanced security and can be created and managed in your account settings. They are ideal for API integrations, automated scripts, and CI/CD pipelines. Tokens can have different permissions, including:

  • can_create_bug_report: Allows creating bug reports
  • can_create_feature_request: Allows creating feature requests
  • can_read_release_list: Allows listing releases
  • can_create_release: Allows creating new releases dynamically via release_label
  • can_update_issue: Allows updating existing issues
  • can_list_issues: Allows listing project issues For more information about Personal Access Tokens, see: https://betahub.io/docs/account/#personal-access-tokens
Path Parameters
Name Type Description
project_id required string
Header Parameters
Name Type Description
BetaHub-Project-ID required string BetaHub project ID, the same as the project_id
cURL
curl \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "BetaHub-Project-ID: 123" \
  "https://app.betahub.io/projects/123/game_facts.json"
Ruby
require "net/http"

uri = URI("https://app.betahub.io/projects/123/game_facts.json")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Get.new(uri)
request["Authorization"] = "Bearer YOUR_API_TOKEN"
request["BetaHub-Project-ID"] = "123"

response = http.request(request)
puts response.body
Python
import requests

response = requests.get(
    "https://app.betahub.io/projects/123/game_facts.json",
    headers={"Authorization": "Bearer YOUR_API_TOKEN", "BetaHub-Project-ID": "123"}
)
print(response.json())
JavaScript
const response = await fetch("https://app.betahub.io/projects/123/game_facts.json", {
  headers: {
    "Authorization": "Bearer YOUR_API_TOKEN",
    "BetaHub-Project-ID": "123"
  }
});
const data = await response.json();
Java
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://app.betahub.io/projects/123/game_facts.json"))
    .header("Authorization", "Bearer YOUR_API_TOKEN")
    .header("BetaHub-Project-ID", "123")
    .GET()
    .build();
HttpResponse<String> response = client.send(
    request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
Responses
application/json
{
  "description": "A fantasy RPG set in a magical world",
  "genre": "Action RPG",
  "target_audience": "Teen",
  "platforms": [
    "PC",
    "PlayStation",
    "Xbox"
  ],
  "core_mechanics": {
    "key_features": [
      "Magic system",
      "Character progression",
      "Crafting"
    ],
    "game_modes": [
      "Single Player",
      "Cooperative"
    ],
    "controls": {
      "pc": {
        "move": "WASD",
        "attack": "Left Click"
      },
      "console": {
        "move": "Left Stick",
        "attack": "X Button"
      }
    }
  },
  "technical_specifications": {
    "supported_platforms": [
      "Windows",
      "Linux",
      "macOS"
    ],
    "minimum_system_requirements": {
      "ram": "8GB",
      "cpu": "Intel i5",
      "gpu": "GTX 1060"
    }
  },
  "glossary": {
    "items": [
      {
        "term": "Mana Potion",
        "definition": "Restores magical energy"
      }
    ],
    "characters": [
      {
        "term": "Elder Mage",
        "definition": "Wise spellcaster and quest giver"
      }
    ],
    "events": [],
    "locations": [],
    "other_terms": []
  },
  "project": {
    "id": "pr-123456",
    "name": "My Fantasy Game"
  },
  "meta": {
    "created_at": "2024-10-03T12:34:56Z",
    "updated_at": "2024-10-03T14:22:10Z"
  }
}
application/json
{
  "error": "string",
  "status": "string"
}
application/json
{
  "error": "string",
  "status": "string"
}
Updates game facts for a project with new JSON data. This endpoint can be used to programmatically import game facts from external sources or update specific sections of the game facts. If no game facts exist for the project, new ones will be created. All validation rules apply, including field length limits and required nested structures.
Authorization required

Authorization header for API access. Supports multiple authentication methods:

  1. Anonymous access: FormUser anonymous - for public operations
  2. Token-based access: FormUser tkn-{token} - for authenticated operations with legacy tokens
  3. Token with Email: FormUser tkn-{token},email:{email} - creates/links virtual user by email
  4. Token with Discord ID: FormUser tkn-{token},discord_id:{discord_id} - creates/links virtual user by Discord ID
  5. Token with JWT: FormUser tkn-{token},{jwt_token} - user identification with JWT token (legacy)
  6. Personal Access Tokens: Bearer YOUR_TOKEN_HERE - recommended for API integrations

Virtual User Creation

When using email: or discord_id: formats with FormUser tokens, the system automatically creates or reuses virtual users. Virtual users are accounts created on-the-fly for form submissions without requiring full user registration. This is useful for:

  • Linking form submissions to specific individuals by email or Discord ID
  • Tracking submissions across multiple reports from the same person
  • Creating user profiles without sign-up workflows

Virtual users created this way are marked as virtual accounts and work across Issues, Feature Requests, and Support Tickets.

Validation Rules:

  • email: format must match RFC 5322 email format. Invalid emails will fall back to anonymous access.
  • discord_id: format must be numeric (digits only). Invalid discord_ids will fall back to anonymous access.
  • Invalid identifiers do not cause HTTP errors; they fall back to anonymous authentication for graceful degradation.

Personal Access Tokens

Personal Access Tokens provide enhanced security and can be created and managed in your account settings. They are ideal for API integrations, automated scripts, and CI/CD pipelines. Tokens can have different permissions, including:

  • can_create_bug_report: Allows creating bug reports
  • can_create_feature_request: Allows creating feature requests
  • can_read_release_list: Allows listing releases
  • can_create_release: Allows creating new releases dynamically via release_label
  • can_update_issue: Allows updating existing issues
  • can_list_issues: Allows listing project issues For more information about Personal Access Tokens, see: https://betahub.io/docs/account/#personal-access-tokens
Path Parameters
Name Type Description
project_id required string
Header Parameters
Name Type Description
BetaHub-Project-ID required string BetaHub project ID, the same as the project_id
Request Body
application/json
  • game_fact object optional
    • description string optional Description of the game (max 1000 characters)
    • genre string optional Game genre (max 100 characters)
    • target_audience string optional Target audience for the game (max 300 characters)
    • ui_ux_considerations string optional User interface and experience considerations
    • platforms array[string] optional Supported platforms (max 10 items)
    • core_mechanics object optional
      • key_features array[string] Key game features
      • game_modes array[string] Available game modes
      • controls object
    • technical_specifications object optional
      • supported_platforms array[string] Technically supported platforms
      • minimum_system_requirements object Minimum system requirements
    • game_progression object optional
      • level_design string Level design information
      • progression_system string Character/game progression system
    • bug_reporting_guidelines object optional
      • critical_components array[string] Critical game components for bug reporting
      • non_critical_components array[string] Non-critical game components
      • known_bugs array[string] List of known bugs
    • glossary object optional
      • items array[object] Game items glossary
      • characters array[object] Game characters glossary
      • events array[object] Game events glossary
      • locations array[object] Game locations glossary
      • other_terms array[object] Other game terms glossary
    • save_load_system object optional
      • save_method string How the game saves data
      • known_issues array[string] Known save/load issues
    • multiplayer_online_features object optional
      • supported_modes array[string] Supported multiplayer modes
      • networking object
    • localization object optional
      • supported_languages array[string] Supported languages
      • known_issues array[string] Known localization issues
cURL
curl \
  -X PATCH \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "BetaHub-Project-ID: 123" \
  -H "Content-Type: application/json" \
  -d '{
  "game_fact": {
    "description": "string",
    "genre": "string",
    "target_audience": "string",
    "ui_ux_considerations": "string",
    "platforms": [
      "string"
    ],
    "core_mechanics": {
      "key_features": [
        "string"
      ],
      "game_modes": [
        "string"
      ],
      "controls": {
        "pc": {},
        "console": {}
      }
    },
    "technical_specifications": {
      "supported_platforms": [
        "string"
      ],
      "minimum_system_requirements": {}
    },
    "game_progression": {
      "level_design": "string",
      "progression_system": "string"
    },
    "bug_reporting_guidelines": {
      "critical_components": [
        "string"
      ],
      "non_critical_components": [
        "string"
      ],
      "known_bugs": [
        "string"
      ]
    },
    "glossary": {
      "items": [
        {}
      ],
      "characters": [
        {}
      ],
      "events": [
        {}
      ],
      "locations": [
        {}
      ],
      "other_terms": [
        {}
      ]
    },
    "save_load_system": {
      "save_method": "string",
      "known_issues": [
        "string"
      ]
    },
    "multiplayer_online_features": {
      "supported_modes": [
        "string"
      ],
      "networking": {
        "server_type": "string",
        "known_issues": [
          null
        ]
      }
    },
    "localization": {
      "supported_languages": [
        "string"
      ],
      "known_issues": [
        "string"
      ]
    }
  }
}' \
  "https://app.betahub.io/projects/123/game_facts.json"
Ruby
require "net/http"
require "json"

uri = URI("https://app.betahub.io/projects/123/game_facts.json")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Patch.new(uri)
request["Authorization"] = "Bearer YOUR_API_TOKEN"
request["BetaHub-Project-ID"] = "123"
request["Content-Type"] = "application/json"
request.body = {
  "game_fact": {
    "description": "string",
    "genre": "string",
    "target_audience": "string",
    "ui_ux_considerations": "string",
    "platforms": [
      "string"
    ],
    "core_mechanics": {
      "key_features": [
        "string"
      ],
      "game_modes": [
        "string"
      ],
      "controls": {
        "pc": {},
        "console": {}
      }
    },
    "technical_specifications": {
      "supported_platforms": [
        "string"
      ],
      "minimum_system_requirements": {}
    },
    "game_progression": {
      "level_design": "string",
      "progression_system": "string"
    },
    "bug_reporting_guidelines": {
      "critical_components": [
        "string"
      ],
      "non_critical_components": [
        "string"
      ],
      "known_bugs": [
        "string"
      ]
    },
    "glossary": {
      "items": [
        {}
      ],
      "characters": [
        {}
      ],
      "events": [
        {}
      ],
      "locations": [
        {}
      ],
      "other_terms": [
        {}
      ]
    },
    "save_load_system": {
      "save_method": "string",
      "known_issues": [
        "string"
      ]
    },
    "multiplayer_online_features": {
      "supported_modes": [
        "string"
      ],
      "networking": {
        "server_type": "string",
        "known_issues": [
          null
        ]
      }
    },
    "localization": {
      "supported_languages": [
        "string"
      ],
      "known_issues": [
        "string"
      ]
    }
  }
}

response = http.request(request)
puts response.body
Python
import requests

response = requests.patch(
    "https://app.betahub.io/projects/123/game_facts.json",
    headers={"Authorization": "Bearer YOUR_API_TOKEN", "BetaHub-Project-ID": "123"},
    json={
      "game_fact": {
        "description": "string",
        "genre": "string",
        "target_audience": "string",
        "ui_ux_considerations": "string",
        "platforms": [
          "string"
        ],
        "core_mechanics": {
          "key_features": [
            "string"
          ],
          "game_modes": [
            "string"
          ],
          "controls": {
            "pc": {},
            "console": {}
          }
        },
        "technical_specifications": {
          "supported_platforms": [
            "string"
          ],
          "minimum_system_requirements": {}
        },
        "game_progression": {
          "level_design": "string",
          "progression_system": "string"
        },
        "bug_reporting_guidelines": {
          "critical_components": [
            "string"
          ],
          "non_critical_components": [
            "string"
          ],
          "known_bugs": [
            "string"
          ]
        },
        "glossary": {
          "items": [
            {}
          ],
          "characters": [
            {}
          ],
          "events": [
            {}
          ],
          "locations": [
            {}
          ],
          "other_terms": [
            {}
          ]
        },
        "save_load_system": {
          "save_method": "string",
          "known_issues": [
            "string"
          ]
        },
        "multiplayer_online_features": {
          "supported_modes": [
            "string"
          ],
          "networking": {
            "server_type": "string",
            "known_issues": [
              null
            ]
          }
        },
        "localization": {
          "supported_languages": [
            "string"
          ],
          "known_issues": [
            "string"
          ]
        }
      }
    }
)
print(response.json())
JavaScript
const response = await fetch("https://app.betahub.io/projects/123/game_facts.json", {
  method: "PATCH",
  headers: {
    "Authorization": "Bearer YOUR_API_TOKEN",
    "BetaHub-Project-ID": "123",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    "game_fact": {
      "description": "string",
      "genre": "string",
      "target_audience": "string",
      "ui_ux_considerations": "string",
      "platforms": [
        "string"
      ],
      "core_mechanics": {
        "key_features": [
          "string"
        ],
        "game_modes": [
          "string"
        ],
        "controls": {
          "pc": {},
          "console": {}
        }
      },
      "technical_specifications": {
        "supported_platforms": [
          "string"
        ],
        "minimum_system_requirements": {}
      },
      "game_progression": {
        "level_design": "string",
        "progression_system": "string"
      },
      "bug_reporting_guidelines": {
        "critical_components": [
          "string"
        ],
        "non_critical_components": [
          "string"
        ],
        "known_bugs": [
          "string"
        ]
      },
      "glossary": {
        "items": [
          {}
        ],
        "characters": [
          {}
        ],
        "events": [
          {}
        ],
        "locations": [
          {}
        ],
        "other_terms": [
          {}
        ]
      },
      "save_load_system": {
        "save_method": "string",
        "known_issues": [
          "string"
        ]
      },
      "multiplayer_online_features": {
        "supported_modes": [
          "string"
        ],
        "networking": {
          "server_type": "string",
          "known_issues": [
            null
          ]
        }
      },
      "localization": {
        "supported_languages": [
          "string"
        ],
        "known_issues": [
          "string"
        ]
      }
    }
  })
});
const data = await response.json();
Java
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://app.betahub.io/projects/123/game_facts.json"))
    .header("Authorization", "Bearer YOUR_API_TOKEN")
    .header("BetaHub-Project-ID", "123")
    .header("Content-Type", "application/json")
    .PATCH(HttpRequest.BodyPublishers.ofString("{\"game_fact\":{\"description\":\"string\",\"genre\":\"string\",\"target_audience\":\"string\",\"ui_ux_considerations\":\"string\",\"platforms\":[\"string\"],\"core_mechanics\":{\"key_features\":[\"string\"],\"game_modes\":[\"string\"],\"controls\":{\"pc\":{},\"console\":{}}},\"technical_specifications\":{\"supported_platforms\":[\"string\"],\"minimum_system_requirements\":{}},\"game_progression\":{\"level_design\":\"string\",\"progression_system\":\"string\"},\"bug_reporting_guidelines\":{\"critical_components\":[\"string\"],\"non_critical_components\":[\"string\"],\"known_bugs\":[\"string\"]},\"glossary\":{\"items\":[{}],\"characters\":[{}],\"events\":[{}],\"locations\":[{}],\"other_terms\":[{}]},\"save_load_system\":{\"save_method\":\"string\",\"known_issues\":[\"string\"]},\"multiplayer_online_features\":{\"supported_modes\":[\"string\"],\"networking\":{\"server_type\":\"string\",\"known_issues\":[null]}},\"localization\":{\"supported_languages\":[\"string\"],\"known_issues\":[\"string\"]}}}"))
    .build();
HttpResponse<String> response = client.send(
    request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
Request Body
{
  "game_fact": {
    "description": "string",
    "genre": "string",
    "target_audience": "string",
    "ui_ux_considerations": "string",
    "platforms": [
      "string"
    ],
    "core_mechanics": {
      "key_features": [
        "string"
      ],
      "game_modes": [
        "string"
      ],
      "controls": {
        "pc": {},
        "console": {}
      }
    },
    "technical_specifications": {
      "supported_platforms": [
        "string"
      ],
      "minimum_system_requirements": {}
    },
    "game_progression": {
      "level_design": "string",
      "progression_system": "string"
    },
    "bug_reporting_guidelines": {
      "critical_components": [
        "string"
      ],
      "non_critical_components": [
        "string"
      ],
      "known_bugs": [
        "string"
      ]
    },
    "glossary": {
      "items": [
        {}
      ],
      "characters": [
        {}
      ],
      "events": [
        {}
      ],
      "locations": [
        {}
      ],
      "other_terms": [
        {}
      ]
    },
    "save_load_system": {
      "save_method": "string",
      "known_issues": [
        "string"
      ]
    },
    "multiplayer_online_features": {
      "supported_modes": [
        "string"
      ],
      "networking": {
        "server_type": "string",
        "known_issues": [
          null
        ]
      }
    },
    "localization": {
      "supported_languages": [
        "string"
      ],
      "known_issues": [
        "string"
      ]
    }
  }
}
Responses
application/json
{
  "description": "Updated game description",
  "genre": "Action RPG",
  "target_audience": "Teen",
  "platforms": [
    "PC",
    "PlayStation"
  ],
  "core_mechanics": {
    "key_features": [
      "Updated feature"
    ],
    "game_modes": [
      "Single Player"
    ]
  },
  "project": {
    "id": "pr-123456",
    "name": "My Fantasy Game"
  },
  "meta": {
    "created_at": "2024-10-03T12:34:56Z",
    "updated_at": "2024-10-03T16:45:30Z"
  }
}
application/json
{
  "error": "string",
  "status": "string"
}
application/json
{
  "error": "string",
  "status": "string"
}
application/json
{
  "errors": [
    "Description is too long (maximum is 1000 characters)"
  ]
}

Playtime Sessions

This endpoint is used to create a new playtime session for a project. The playtime session is used to track the user’s playtime in the project. You can pass any key=value tag pairs in the request body to associate with the playtime session. For instance, you can pass playtime_session[platform]=ios to associate the playtime session with the iOS platform. The returned is a uuid that can be used to update the playtime session using the PUT endpoint.
Authorization required

Authorization header for API access. Supports multiple authentication methods:

  1. Anonymous access: FormUser anonymous - for public operations
  2. Token-based access: FormUser tkn-{token} - for authenticated operations with legacy tokens
  3. Token with Email: FormUser tkn-{token},email:{email} - creates/links virtual user by email
  4. Token with Discord ID: FormUser tkn-{token},discord_id:{discord_id} - creates/links virtual user by Discord ID
  5. Token with JWT: FormUser tkn-{token},{jwt_token} - user identification with JWT token (legacy)
  6. Personal Access Tokens: Bearer YOUR_TOKEN_HERE - recommended for API integrations

Virtual User Creation

When using email: or discord_id: formats with FormUser tokens, the system automatically creates or reuses virtual users. Virtual users are accounts created on-the-fly for form submissions without requiring full user registration. This is useful for:

  • Linking form submissions to specific individuals by email or Discord ID
  • Tracking submissions across multiple reports from the same person
  • Creating user profiles without sign-up workflows

Virtual users created this way are marked as virtual accounts and work across Issues, Feature Requests, and Support Tickets.

Validation Rules:

  • email: format must match RFC 5322 email format. Invalid emails will fall back to anonymous access.
  • discord_id: format must be numeric (digits only). Invalid discord_ids will fall back to anonymous access.
  • Invalid identifiers do not cause HTTP errors; they fall back to anonymous authentication for graceful degradation.

Personal Access Tokens

Personal Access Tokens provide enhanced security and can be created and managed in your account settings. They are ideal for API integrations, automated scripts, and CI/CD pipelines. Tokens can have different permissions, including:

  • can_create_bug_report: Allows creating bug reports
  • can_create_feature_request: Allows creating feature requests
  • can_read_release_list: Allows listing releases
  • can_create_release: Allows creating new releases dynamically via release_label
  • can_update_issue: Allows updating existing issues
  • can_list_issues: Allows listing project issues For more information about Personal Access Tokens, see: https://betahub.io/docs/account/#personal-access-tokens
Path Parameters
Name Type Description
project_id required string
Header Parameters
Name Type Description
BetaHub-Project-ID required string BetaHub project ID, the same as the project_id
Request Body
application/json
  • playtime_session[tags] string required Key-value pairs to associate with the playtime session.
cURL
curl \
  -X POST \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "BetaHub-Project-ID: 123" \
  -H "Content-Type: application/json" \
  -d '{
  "playtime_session[tags]": "string"
}' \
  "https://app.betahub.io/projects/123/playtime_sessions"
Ruby
require "net/http"
require "json"

uri = URI("https://app.betahub.io/projects/123/playtime_sessions")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Post.new(uri)
request["Authorization"] = "Bearer YOUR_API_TOKEN"
request["BetaHub-Project-ID"] = "123"
request["Content-Type"] = "application/json"
request.body = {
  "playtime_session[tags]": "string"
}

response = http.request(request)
puts response.body
Python
import requests

response = requests.post(
    "https://app.betahub.io/projects/123/playtime_sessions",
    headers={"Authorization": "Bearer YOUR_API_TOKEN", "BetaHub-Project-ID": "123"},
    json={
      "playtime_session[tags]": "string"
    }
)
print(response.json())
JavaScript
const response = await fetch("https://app.betahub.io/projects/123/playtime_sessions", {
  method: "POST",
  headers: {
    "Authorization": "Bearer YOUR_API_TOKEN",
    "BetaHub-Project-ID": "123",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    "playtime_session[tags]": "string"
  })
});
const data = await response.json();
Java
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://app.betahub.io/projects/123/playtime_sessions"))
    .header("Authorization", "Bearer YOUR_API_TOKEN")
    .header("BetaHub-Project-ID", "123")
    .header("Content-Type", "application/json")
    .POST(HttpRequest.BodyPublishers.ofString("{\"playtime_session[tags]\":\"string\"}"))
    .build();
HttpResponse<String> response = client.send(
    request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
Request Body
{
  "playtime_session[tags]": "string"
}
Responses
application/json
{
  "playtime_session[tags]": "platform=ios"
}
This endpoint is used to update a playtime session for a project. The playtime session is used to track the user’s playtime in the project. Use the playtime session ID returned from the POST endpoint to update the playtime session. Call this endpoint no longer than every 5 minutes to update the playtime session.
Authorization required

Authorization header for API access. Supports multiple authentication methods:

  1. Anonymous access: FormUser anonymous - for public operations
  2. Token-based access: FormUser tkn-{token} - for authenticated operations with legacy tokens
  3. Token with Email: FormUser tkn-{token},email:{email} - creates/links virtual user by email
  4. Token with Discord ID: FormUser tkn-{token},discord_id:{discord_id} - creates/links virtual user by Discord ID
  5. Token with JWT: FormUser tkn-{token},{jwt_token} - user identification with JWT token (legacy)
  6. Personal Access Tokens: Bearer YOUR_TOKEN_HERE - recommended for API integrations

Virtual User Creation

When using email: or discord_id: formats with FormUser tokens, the system automatically creates or reuses virtual users. Virtual users are accounts created on-the-fly for form submissions without requiring full user registration. This is useful for:

  • Linking form submissions to specific individuals by email or Discord ID
  • Tracking submissions across multiple reports from the same person
  • Creating user profiles without sign-up workflows

Virtual users created this way are marked as virtual accounts and work across Issues, Feature Requests, and Support Tickets.

Validation Rules:

  • email: format must match RFC 5322 email format. Invalid emails will fall back to anonymous access.
  • discord_id: format must be numeric (digits only). Invalid discord_ids will fall back to anonymous access.
  • Invalid identifiers do not cause HTTP errors; they fall back to anonymous authentication for graceful degradation.

Personal Access Tokens

Personal Access Tokens provide enhanced security and can be created and managed in your account settings. They are ideal for API integrations, automated scripts, and CI/CD pipelines. Tokens can have different permissions, including:

  • can_create_bug_report: Allows creating bug reports
  • can_create_feature_request: Allows creating feature requests
  • can_read_release_list: Allows listing releases
  • can_create_release: Allows creating new releases dynamically via release_label
  • can_update_issue: Allows updating existing issues
  • can_list_issues: Allows listing project issues For more information about Personal Access Tokens, see: https://betahub.io/docs/account/#personal-access-tokens
Path Parameters
Name Type Description
project_id required string
playtime_session_id required string
Header Parameters
Name Type Description
BetaHub-Project-ID required string BetaHub project ID, the same as the project_id
cURL
curl \
  -X PUT \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "BetaHub-Project-ID: 123" \
  "https://app.betahub.io/projects/123/playtime_sessions/123"
Ruby
require "net/http"

uri = URI("https://app.betahub.io/projects/123/playtime_sessions/123")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Put.new(uri)
request["Authorization"] = "Bearer YOUR_API_TOKEN"
request["BetaHub-Project-ID"] = "123"

response = http.request(request)
puts response.body
Python
import requests

response = requests.put(
    "https://app.betahub.io/projects/123/playtime_sessions/123",
    headers={"Authorization": "Bearer YOUR_API_TOKEN", "BetaHub-Project-ID": "123"}
)
print(response.json())
JavaScript
const response = await fetch("https://app.betahub.io/projects/123/playtime_sessions/123", {
  method: "PUT",
  headers: {
    "Authorization": "Bearer YOUR_API_TOKEN",
    "BetaHub-Project-ID": "123"
  }
});
const data = await response.json();
Java
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://app.betahub.io/projects/123/playtime_sessions/123"))
    .header("Authorization", "Bearer YOUR_API_TOKEN")
    .header("BetaHub-Project-ID", "123")
    .method("PUT", HttpRequest.BodyPublishers.noBody())
    .build();
HttpResponse<String> response = client.send(
    request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
Responses
application/json
{
  "id": "1234abc"
}
application/json
{
  "error": "string",
  "status": "string"
}
application/json
{
  "error": "string",
  "status": "string"
}

Custom Fields

Returns a paginated list of custom fields configured for a project, filtered by the entity type they apply to. Token-based access (FormUser, Discord bot) returns a limited set of field properties. Regular authenticated users see the full details.
Authorization required

Authorization header for API access. Supports multiple authentication methods:

  1. Anonymous access: FormUser anonymous - for public operations
  2. Token-based access: FormUser tkn-{token} - for authenticated operations with legacy tokens
  3. Token with Email: FormUser tkn-{token},email:{email} - creates/links virtual user by email
  4. Token with Discord ID: FormUser tkn-{token},discord_id:{discord_id} - creates/links virtual user by Discord ID
  5. Token with JWT: FormUser tkn-{token},{jwt_token} - user identification with JWT token (legacy)
  6. Personal Access Tokens: Bearer YOUR_TOKEN_HERE - recommended for API integrations

Virtual User Creation

When using email: or discord_id: formats with FormUser tokens, the system automatically creates or reuses virtual users. Virtual users are accounts created on-the-fly for form submissions without requiring full user registration. This is useful for:

  • Linking form submissions to specific individuals by email or Discord ID
  • Tracking submissions across multiple reports from the same person
  • Creating user profiles without sign-up workflows

Virtual users created this way are marked as virtual accounts and work across Issues, Feature Requests, and Support Tickets.

Validation Rules:

  • email: format must match RFC 5322 email format. Invalid emails will fall back to anonymous access.
  • discord_id: format must be numeric (digits only). Invalid discord_ids will fall back to anonymous access.
  • Invalid identifiers do not cause HTTP errors; they fall back to anonymous authentication for graceful degradation.

Personal Access Tokens

Personal Access Tokens provide enhanced security and can be created and managed in your account settings. They are ideal for API integrations, automated scripts, and CI/CD pipelines. Tokens can have different permissions, including:

  • can_create_bug_report: Allows creating bug reports
  • can_create_feature_request: Allows creating feature requests
  • can_read_release_list: Allows listing releases
  • can_create_release: Allows creating new releases dynamically via release_label
  • can_update_issue: Allows updating existing issues
  • can_list_issues: Allows listing project issues For more information about Personal Access Tokens, see: https://betahub.io/docs/account/#personal-access-tokens
Path Parameters
Name Type Description
project_id required string
Query Parameters
Name Type Description
applies_to optional string Filter by entity type the custom fields apply to
issue feature_request ticket
Default: issue
page optional integer Page number for pagination (default: 1)
Header Parameters
Name Type Description
BetaHub-Project-ID required string BetaHub project ID, the same as the project_id
cURL
curl \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "BetaHub-Project-ID: 123" \
  "https://app.betahub.io/projects/123/custom_fields.json?applies_to=issue&page=123"
Ruby
require "net/http"

uri = URI("https://app.betahub.io/projects/123/custom_fields.json?applies_to=issue&page=123")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Get.new(uri)
request["Authorization"] = "Bearer YOUR_API_TOKEN"
request["BetaHub-Project-ID"] = "123"

response = http.request(request)
puts response.body
Python
import requests

response = requests.get(
    "https://app.betahub.io/projects/123/custom_fields.json?applies_to=issue&page=123",
    headers={"Authorization": "Bearer YOUR_API_TOKEN", "BetaHub-Project-ID": "123"}
)
print(response.json())
JavaScript
const response = await fetch("https://app.betahub.io/projects/123/custom_fields.json?applies_to=issue&page=123", {
  headers: {
    "Authorization": "Bearer YOUR_API_TOKEN",
    "BetaHub-Project-ID": "123"
  }
});
const data = await response.json();
Java
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://app.betahub.io/projects/123/custom_fields.json?applies_to=issue&page=123"))
    .header("Authorization", "Bearer YOUR_API_TOKEN")
    .header("BetaHub-Project-ID", "123")
    .GET()
    .build();
HttpResponse<String> response = client.send(
    request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
Responses
application/json
{
  "custom_fields": [
    {
      "id": 0,
      "ident": "string",
      "name": "string",
      "field_type": "string",
      "required": true,
      "tester_settable": true,
      "tester_viewable": true,
      "options": {},
      "applies_to": "issue",
      "created_at": "2026-03-12T10:30:00Z",
      "updated_at": "2026-03-12T10:30:00Z"
    }
  ],
  "custom_issue_fields": [
    {
      "id": 0,
      "ident": "string",
      "name": "string",
      "field_type": "string",
      "required": true,
      "tester_settable": true,
      "tester_viewable": true,
      "options": {},
      "applies_to": "issue",
      "created_at": "2026-03-12T10:30:00Z",
      "updated_at": "2026-03-12T10:30:00Z"
    }
  ],
  "pagination": {
    "current_page": 0,
    "total_pages": 0,
    "total_count": 0,
    "per_page": 0
  },
  "project_id": 0,
  "applies_to": "string"
}
application/json
{
  "error": "string",
  "status": "string"
}

Issue Statuses

Returns the ordered list of issue statuses configured for a project. Each status includes its display name, behavioral category, and whether it is a system-defined status. Useful for populating status dropdowns or mapping status keys to display names.
Authorization required

Authorization header for API access. Supports multiple authentication methods:

  1. Anonymous access: FormUser anonymous - for public operations
  2. Token-based access: FormUser tkn-{token} - for authenticated operations with legacy tokens
  3. Token with Email: FormUser tkn-{token},email:{email} - creates/links virtual user by email
  4. Token with Discord ID: FormUser tkn-{token},discord_id:{discord_id} - creates/links virtual user by Discord ID
  5. Token with JWT: FormUser tkn-{token},{jwt_token} - user identification with JWT token (legacy)
  6. Personal Access Tokens: Bearer YOUR_TOKEN_HERE - recommended for API integrations

Virtual User Creation

When using email: or discord_id: formats with FormUser tokens, the system automatically creates or reuses virtual users. Virtual users are accounts created on-the-fly for form submissions without requiring full user registration. This is useful for:

  • Linking form submissions to specific individuals by email or Discord ID
  • Tracking submissions across multiple reports from the same person
  • Creating user profiles without sign-up workflows

Virtual users created this way are marked as virtual accounts and work across Issues, Feature Requests, and Support Tickets.

Validation Rules:

  • email: format must match RFC 5322 email format. Invalid emails will fall back to anonymous access.
  • discord_id: format must be numeric (digits only). Invalid discord_ids will fall back to anonymous access.
  • Invalid identifiers do not cause HTTP errors; they fall back to anonymous authentication for graceful degradation.

Personal Access Tokens

Personal Access Tokens provide enhanced security and can be created and managed in your account settings. They are ideal for API integrations, automated scripts, and CI/CD pipelines. Tokens can have different permissions, including:

  • can_create_bug_report: Allows creating bug reports
  • can_create_feature_request: Allows creating feature requests
  • can_read_release_list: Allows listing releases
  • can_create_release: Allows creating new releases dynamically via release_label
  • can_update_issue: Allows updating existing issues
  • can_list_issues: Allows listing project issues For more information about Personal Access Tokens, see: https://betahub.io/docs/account/#personal-access-tokens
Path Parameters
Name Type Description
project_id required string
Header Parameters
Name Type Description
BetaHub-Project-ID required string BetaHub project ID, the same as the project_id
cURL
curl \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "BetaHub-Project-ID: 123" \
  "https://app.betahub.io/projects/123/issue_statuses.json"
Ruby
require "net/http"

uri = URI("https://app.betahub.io/projects/123/issue_statuses.json")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Get.new(uri)
request["Authorization"] = "Bearer YOUR_API_TOKEN"
request["BetaHub-Project-ID"] = "123"

response = http.request(request)
puts response.body
Python
import requests

response = requests.get(
    "https://app.betahub.io/projects/123/issue_statuses.json",
    headers={"Authorization": "Bearer YOUR_API_TOKEN", "BetaHub-Project-ID": "123"}
)
print(response.json())
JavaScript
const response = await fetch("https://app.betahub.io/projects/123/issue_statuses.json", {
  headers: {
    "Authorization": "Bearer YOUR_API_TOKEN",
    "BetaHub-Project-ID": "123"
  }
});
const data = await response.json();
Java
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://app.betahub.io/projects/123/issue_statuses.json"))
    .header("Authorization", "Bearer YOUR_API_TOKEN")
    .header("BetaHub-Project-ID", "123")
    .GET()
    .build();
HttpResponse<String> response = client.send(
    request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
Responses
application/json
{
  "issue_statuses": [
    {
      "key": "string",
      "display_name": "string",
      "behavior_category": "in_progress",
      "system_status": true
    }
  ]
}
application/json
{
  "error": "string",
  "status": "string"
}

Issue Tags

Returns a paginated list of issue tags configured for a project. Tags are returned as a tree structure with parent tags containing their sub-tags. Only top-level parent tags are returned at the root level.
Authorization required

Authorization header for API access. Supports multiple authentication methods:

  1. Anonymous access: FormUser anonymous - for public operations
  2. Token-based access: FormUser tkn-{token} - for authenticated operations with legacy tokens
  3. Token with Email: FormUser tkn-{token},email:{email} - creates/links virtual user by email
  4. Token with Discord ID: FormUser tkn-{token},discord_id:{discord_id} - creates/links virtual user by Discord ID
  5. Token with JWT: FormUser tkn-{token},{jwt_token} - user identification with JWT token (legacy)
  6. Personal Access Tokens: Bearer YOUR_TOKEN_HERE - recommended for API integrations

Virtual User Creation

When using email: or discord_id: formats with FormUser tokens, the system automatically creates or reuses virtual users. Virtual users are accounts created on-the-fly for form submissions without requiring full user registration. This is useful for:

  • Linking form submissions to specific individuals by email or Discord ID
  • Tracking submissions across multiple reports from the same person
  • Creating user profiles without sign-up workflows

Virtual users created this way are marked as virtual accounts and work across Issues, Feature Requests, and Support Tickets.

Validation Rules:

  • email: format must match RFC 5322 email format. Invalid emails will fall back to anonymous access.
  • discord_id: format must be numeric (digits only). Invalid discord_ids will fall back to anonymous access.
  • Invalid identifiers do not cause HTTP errors; they fall back to anonymous authentication for graceful degradation.

Personal Access Tokens

Personal Access Tokens provide enhanced security and can be created and managed in your account settings. They are ideal for API integrations, automated scripts, and CI/CD pipelines. Tokens can have different permissions, including:

  • can_create_bug_report: Allows creating bug reports
  • can_create_feature_request: Allows creating feature requests
  • can_read_release_list: Allows listing releases
  • can_create_release: Allows creating new releases dynamically via release_label
  • can_update_issue: Allows updating existing issues
  • can_list_issues: Allows listing project issues For more information about Personal Access Tokens, see: https://betahub.io/docs/account/#personal-access-tokens
Path Parameters
Name Type Description
project_id required string
Query Parameters
Name Type Description
page optional integer Page number for pagination (default: 1)
Header Parameters
Name Type Description
BetaHub-Project-ID required string BetaHub project ID, the same as the project_id
cURL
curl \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "BetaHub-Project-ID: 123" \
  "https://app.betahub.io/projects/123/issue_tags.json?page=123"
Ruby
require "net/http"

uri = URI("https://app.betahub.io/projects/123/issue_tags.json?page=123")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Get.new(uri)
request["Authorization"] = "Bearer YOUR_API_TOKEN"
request["BetaHub-Project-ID"] = "123"

response = http.request(request)
puts response.body
Python
import requests

response = requests.get(
    "https://app.betahub.io/projects/123/issue_tags.json?page=123",
    headers={"Authorization": "Bearer YOUR_API_TOKEN", "BetaHub-Project-ID": "123"}
)
print(response.json())
JavaScript
const response = await fetch("https://app.betahub.io/projects/123/issue_tags.json?page=123", {
  headers: {
    "Authorization": "Bearer YOUR_API_TOKEN",
    "BetaHub-Project-ID": "123"
  }
});
const data = await response.json();
Java
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://app.betahub.io/projects/123/issue_tags.json?page=123"))
    .header("Authorization", "Bearer YOUR_API_TOKEN")
    .header("BetaHub-Project-ID", "123")
    .GET()
    .build();
HttpResponse<String> response = client.send(
    request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
Responses
application/json
{
  "tags": [
    {
      "id": 0,
      "name": "string",
      "color": "string",
      "description": "string",
      "parent_tag_id": 0,
      "tag_type": "string",
      "created_at": "2026-03-12T10:30:00Z",
      "updated_at": "2026-03-12T10:30:00Z",
      "sub_tags": [
        {}
      ]
    }
  ],
  "project_id": 0,
  "pagination": {
    "current_page": 0,
    "total_pages": 0,
    "total_count": 0,
    "per_page": 0
  }
}
application/json
{
  "error": "string",
  "status": "string"
}

Profile

Returns the profile of the currently authenticated user, including their display name and all project role assignments.
Authorization required

Authorization header for API access. Supports multiple authentication methods:

  1. Anonymous access: FormUser anonymous - for public operations
  2. Token-based access: FormUser tkn-{token} - for authenticated operations with legacy tokens
  3. Token with Email: FormUser tkn-{token},email:{email} - creates/links virtual user by email
  4. Token with Discord ID: FormUser tkn-{token},discord_id:{discord_id} - creates/links virtual user by Discord ID
  5. Token with JWT: FormUser tkn-{token},{jwt_token} - user identification with JWT token (legacy)
  6. Personal Access Tokens: Bearer YOUR_TOKEN_HERE - recommended for API integrations

Virtual User Creation

When using email: or discord_id: formats with FormUser tokens, the system automatically creates or reuses virtual users. Virtual users are accounts created on-the-fly for form submissions without requiring full user registration. This is useful for:

  • Linking form submissions to specific individuals by email or Discord ID
  • Tracking submissions across multiple reports from the same person
  • Creating user profiles without sign-up workflows

Virtual users created this way are marked as virtual accounts and work across Issues, Feature Requests, and Support Tickets.

Validation Rules:

  • email: format must match RFC 5322 email format. Invalid emails will fall back to anonymous access.
  • discord_id: format must be numeric (digits only). Invalid discord_ids will fall back to anonymous access.
  • Invalid identifiers do not cause HTTP errors; they fall back to anonymous authentication for graceful degradation.

Personal Access Tokens

Personal Access Tokens provide enhanced security and can be created and managed in your account settings. They are ideal for API integrations, automated scripts, and CI/CD pipelines. Tokens can have different permissions, including:

  • can_create_bug_report: Allows creating bug reports
  • can_create_feature_request: Allows creating feature requests
  • can_read_release_list: Allows listing releases
  • can_create_release: Allows creating new releases dynamically via release_label
  • can_update_issue: Allows updating existing issues
  • can_list_issues: Allows listing project issues For more information about Personal Access Tokens, see: https://betahub.io/docs/account/#personal-access-tokens
This endpoint has no query parameters or request body.
cURL
curl \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  "https://app.betahub.io/profiles/me.json"
Ruby
require "net/http"

uri = URI("https://app.betahub.io/profiles/me.json")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Get.new(uri)
request["Authorization"] = "Bearer YOUR_API_TOKEN"

response = http.request(request)
puts response.body
Python
import requests

response = requests.get(
    "https://app.betahub.io/profiles/me.json",
    headers={"Authorization": "Bearer YOUR_API_TOKEN"}
)
print(response.json())
JavaScript
const response = await fetch("https://app.betahub.io/profiles/me.json", {
  headers: {
    "Authorization": "Bearer YOUR_API_TOKEN"
  }
});
const data = await response.json();
Java
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://app.betahub.io/profiles/me.json"))
    .header("Authorization", "Bearer YOUR_API_TOKEN")
    .GET()
    .build();
HttpResponse<String> response = client.send(
    request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
Responses
application/json
{
  "name": "string",
  "roles": [
    {
      "project": {},
      "role": "string"
    }
  ]
}
application/json
{
  "error": "string",
  "status": "string"
}

Comments

Returns detailed information about a specific comment, including the comment body, author, and the parent entity it belongs to.
Authorization required

Authorization header for API access. Supports multiple authentication methods:

  1. Anonymous access: FormUser anonymous - for public operations
  2. Token-based access: FormUser tkn-{token} - for authenticated operations with legacy tokens
  3. Token with Email: FormUser tkn-{token},email:{email} - creates/links virtual user by email
  4. Token with Discord ID: FormUser tkn-{token},discord_id:{discord_id} - creates/links virtual user by Discord ID
  5. Token with JWT: FormUser tkn-{token},{jwt_token} - user identification with JWT token (legacy)
  6. Personal Access Tokens: Bearer YOUR_TOKEN_HERE - recommended for API integrations

Virtual User Creation

When using email: or discord_id: formats with FormUser tokens, the system automatically creates or reuses virtual users. Virtual users are accounts created on-the-fly for form submissions without requiring full user registration. This is useful for:

  • Linking form submissions to specific individuals by email or Discord ID
  • Tracking submissions across multiple reports from the same person
  • Creating user profiles without sign-up workflows

Virtual users created this way are marked as virtual accounts and work across Issues, Feature Requests, and Support Tickets.

Validation Rules:

  • email: format must match RFC 5322 email format. Invalid emails will fall back to anonymous access.
  • discord_id: format must be numeric (digits only). Invalid discord_ids will fall back to anonymous access.
  • Invalid identifiers do not cause HTTP errors; they fall back to anonymous authentication for graceful degradation.

Personal Access Tokens

Personal Access Tokens provide enhanced security and can be created and managed in your account settings. They are ideal for API integrations, automated scripts, and CI/CD pipelines. Tokens can have different permissions, including:

  • can_create_bug_report: Allows creating bug reports
  • can_create_feature_request: Allows creating feature requests
  • can_read_release_list: Allows listing releases
  • can_create_release: Allows creating new releases dynamically via release_label
  • can_update_issue: Allows updating existing issues
  • can_list_issues: Allows listing project issues For more information about Personal Access Tokens, see: https://betahub.io/docs/account/#personal-access-tokens
Path Parameters
Name Type Description
id required integer The comment ID
cURL
curl \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  "https://app.betahub.io/comments/123.json"
Ruby
require "net/http"

uri = URI("https://app.betahub.io/comments/123.json")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Get.new(uri)
request["Authorization"] = "Bearer YOUR_API_TOKEN"

response = http.request(request)
puts response.body
Python
import requests

response = requests.get(
    "https://app.betahub.io/comments/123.json",
    headers={"Authorization": "Bearer YOUR_API_TOKEN"}
)
print(response.json())
JavaScript
const response = await fetch("https://app.betahub.io/comments/123.json", {
  headers: {
    "Authorization": "Bearer YOUR_API_TOKEN"
  }
});
const data = await response.json();
Java
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://app.betahub.io/comments/123.json"))
    .header("Authorization", "Bearer YOUR_API_TOKEN")
    .GET()
    .build();
HttpResponse<String> response = client.send(
    request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
Responses
application/json
{
  "id": 0,
  "body": "string",
  "created_at": "2026-03-12T10:30:00Z",
  "updated_at": "2026-03-12T10:30:00Z",
  "solution": true,
  "private_comment": true,
  "user": {
    "id": 0,
    "name": "string",
    "discord_username": "string"
  },
  "commentable": {
    "id": 0,
    "type": "string"
  }
}
application/json
{
  "error": "string",
  "status": "string"
}
application/json
{
  "error": "string",
  "status": "string"
}

issues

Searches for issues (bug reports) within a project. Uses full-text search powered by Meilisearch to find matching issues based on the query string. Returns matching titles for autocomplete functionality or full issue objects for detailed results. Note: Search is performed across all issues in the project, then filtered by visibility permissions. The search includes issue titles and descriptions.
Authorization required

Authorization header for API access. Supports multiple authentication methods:

  1. Anonymous access: FormUser anonymous - for public operations
  2. Token-based access: FormUser tkn-{token} - for authenticated operations with legacy tokens
  3. Token with Email: FormUser tkn-{token},email:{email} - creates/links virtual user by email
  4. Token with Discord ID: FormUser tkn-{token},discord_id:{discord_id} - creates/links virtual user by Discord ID
  5. Token with JWT: FormUser tkn-{token},{jwt_token} - user identification with JWT token (legacy)
  6. Personal Access Tokens: Bearer YOUR_TOKEN_HERE - recommended for API integrations

Virtual User Creation

When using email: or discord_id: formats with FormUser tokens, the system automatically creates or reuses virtual users. Virtual users are accounts created on-the-fly for form submissions without requiring full user registration. This is useful for:

  • Linking form submissions to specific individuals by email or Discord ID
  • Tracking submissions across multiple reports from the same person
  • Creating user profiles without sign-up workflows

Virtual users created this way are marked as virtual accounts and work across Issues, Feature Requests, and Support Tickets.

Validation Rules:

  • email: format must match RFC 5322 email format. Invalid emails will fall back to anonymous access.
  • discord_id: format must be numeric (digits only). Invalid discord_ids will fall back to anonymous access.
  • Invalid identifiers do not cause HTTP errors; they fall back to anonymous authentication for graceful degradation.

Personal Access Tokens

Personal Access Tokens provide enhanced security and can be created and managed in your account settings. They are ideal for API integrations, automated scripts, and CI/CD pipelines. Tokens can have different permissions, including:

  • can_create_bug_report: Allows creating bug reports
  • can_create_feature_request: Allows creating feature requests
  • can_read_release_list: Allows listing releases
  • can_create_release: Allows creating new releases dynamically via release_label
  • can_update_issue: Allows updating existing issues
  • can_list_issues: Allows listing project issues For more information about Personal Access Tokens, see: https://betahub.io/docs/account/#personal-access-tokens
Path Parameters
Name Type Description
project_id required string
Query Parameters
Name Type Description
query required string The search query string to match against issue titles and descriptions
skip_ids optional string Comma-separated list of issue IDs to exclude from results
partial optional string When set to ‘true’, returns limited results optimized for autocomplete (max 4 results)
true false
scoped_id optional string Instead of searching, find a specific issue by its scoped ID (e.g., “123” or “g-456”)
Header Parameters
Name Type Description
BetaHub-Project-ID required string BetaHub project ID, the same as the project_id
cURL
curl \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "BetaHub-Project-ID: 123" \
  "https://app.betahub.io/projects/123/issues/search.json?query=example&skip_ids=123&partial=true&scoped_id=123"
Ruby
require "net/http"

uri = URI("https://app.betahub.io/projects/123/issues/search.json?query=example&skip_ids=123&partial=true&scoped_id=123")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Get.new(uri)
request["Authorization"] = "Bearer YOUR_API_TOKEN"
request["BetaHub-Project-ID"] = "123"

response = http.request(request)
puts response.body
Python
import requests

response = requests.get(
    "https://app.betahub.io/projects/123/issues/search.json?query=example&skip_ids=123&partial=true&scoped_id=123",
    headers={"Authorization": "Bearer YOUR_API_TOKEN", "BetaHub-Project-ID": "123"}
)
print(response.json())
JavaScript
const response = await fetch("https://app.betahub.io/projects/123/issues/search.json?query=example&skip_ids=123&partial=true&scoped_id=123", {
  headers: {
    "Authorization": "Bearer YOUR_API_TOKEN",
    "BetaHub-Project-ID": "123"
  }
});
const data = await response.json();
Java
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://app.betahub.io/projects/123/issues/search.json?query=example&skip_ids=123&partial=true&scoped_id=123"))
    .header("Authorization", "Bearer YOUR_API_TOKEN")
    .header("BetaHub-Project-ID", "123")
    .GET()
    .build();
HttpResponse<String> response = client.send(
    request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
Responses
application/json
{
  "issues": [
    {
      "id": "1234abc",
      "title": "App crashes on login screen",
      "status": "open",
      "priority": "high",
      "created_at": "2024-10-03T12:34:56Z"
    }
  ],
  "pagination": {
    "current_page": 1,
    "per_page": 25,
    "total_pages": 3,
    "total_count": 68
  },
  "project_id": 123
}
application/json
{
  "error": "string",
  "status": "string"
}
application/json
{
  "error": "string",
  "status": "string"
}
Alternative POST method for searching issues. Accepts the same parameters as the GET method but allows for longer search queries that might exceed URL length limits.
Authorization required

Authorization header for API access. Supports multiple authentication methods:

  1. Anonymous access: FormUser anonymous - for public operations
  2. Token-based access: FormUser tkn-{token} - for authenticated operations with legacy tokens
  3. Token with Email: FormUser tkn-{token},email:{email} - creates/links virtual user by email
  4. Token with Discord ID: FormUser tkn-{token},discord_id:{discord_id} - creates/links virtual user by Discord ID
  5. Token with JWT: FormUser tkn-{token},{jwt_token} - user identification with JWT token (legacy)
  6. Personal Access Tokens: Bearer YOUR_TOKEN_HERE - recommended for API integrations

Virtual User Creation

When using email: or discord_id: formats with FormUser tokens, the system automatically creates or reuses virtual users. Virtual users are accounts created on-the-fly for form submissions without requiring full user registration. This is useful for:

  • Linking form submissions to specific individuals by email or Discord ID
  • Tracking submissions across multiple reports from the same person
  • Creating user profiles without sign-up workflows

Virtual users created this way are marked as virtual accounts and work across Issues, Feature Requests, and Support Tickets.

Validation Rules:

  • email: format must match RFC 5322 email format. Invalid emails will fall back to anonymous access.
  • discord_id: format must be numeric (digits only). Invalid discord_ids will fall back to anonymous access.
  • Invalid identifiers do not cause HTTP errors; they fall back to anonymous authentication for graceful degradation.

Personal Access Tokens

Personal Access Tokens provide enhanced security and can be created and managed in your account settings. They are ideal for API integrations, automated scripts, and CI/CD pipelines. Tokens can have different permissions, including:

  • can_create_bug_report: Allows creating bug reports
  • can_create_feature_request: Allows creating feature requests
  • can_read_release_list: Allows listing releases
  • can_create_release: Allows creating new releases dynamically via release_label
  • can_update_issue: Allows updating existing issues
  • can_list_issues: Allows listing project issues For more information about Personal Access Tokens, see: https://betahub.io/docs/account/#personal-access-tokens
Path Parameters
Name Type Description
project_id required string
Header Parameters
Name Type Description
BetaHub-Project-ID required string BetaHub project ID, the same as the project_id
Request Body
application/x-www-form-urlencoded
  • query string required The search query string to match against issue titles and descriptions
  • skip_ids string optional Comma-separated list of issue IDs to exclude from results
  • partial string optional When set to ‘true’, returns limited results optimized for autocomplete (max 4 results)
    true false
  • scoped_id string optional Instead of searching, find a specific issue by its scoped ID
cURL
curl \
  -X POST \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "BetaHub-Project-ID: 123" \
  -d "query=string" \
  -d "skip_ids=string" \
  -d "partial=true" \
  -d "scoped_id=string" \
  "https://app.betahub.io/projects/123/issues/search.json"
Ruby
require "net/http"
require "json"

uri = URI("https://app.betahub.io/projects/123/issues/search.json")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Post.new(uri)
request["Authorization"] = "Bearer YOUR_API_TOKEN"
request["BetaHub-Project-ID"] = "123"
request.set_form_data({
  "query" => "string",
  "skip_ids" => "string",
  "partial" => "true",
  "scoped_id" => "string"
})

response = http.request(request)
puts response.body
Python
import requests

response = requests.post(
    "https://app.betahub.io/projects/123/issues/search.json",
    headers={"Authorization": "Bearer YOUR_API_TOKEN", "BetaHub-Project-ID": "123"},
    data={"query": "string", "skip_ids": "string", "partial": "true", "scoped_id": "string"}
)
print(response.json())
JavaScript
const response = await fetch("https://app.betahub.io/projects/123/issues/search.json", {
  method: "POST",
  headers: {
    "Authorization": "Bearer YOUR_API_TOKEN",
    "BetaHub-Project-ID": "123"
  }
});
const data = await response.json();
Java
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://app.betahub.io/projects/123/issues/search.json"))
    .header("Authorization", "Bearer YOUR_API_TOKEN")
    .header("BetaHub-Project-ID", "123")
    .header("Content-Type", "application/json")
    .POST(HttpRequest.BodyPublishers.ofString("{\"query\":\"string\",\"skip_ids\":\"string\",\"partial\":\"true\",\"scoped_id\":\"string\"}"))
    .build();
HttpResponse<String> response = client.send(
    request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
Request Body
{
  "query": "string",
  "skip_ids": "string",
  "partial": "true",
  "scoped_id": "string"
}
Responses
application/json
{}
application/json
{
  "error": "string",
  "status": "string"
}
application/json
{
  "error": "string",
  "status": "string"
}