Developer Platform

Open Scoreboard API

Technical documentation for the current v1 REST API, with copyable examples, route-by-route notes, and authenticated personal API key management.

Public developer docs

Tables

Tables expose scoring-surface configuration and let integrations assign synchronized player lists to one or many owned tables.

Available in v1

Use table reads to inspect live scoring targets and their integration-managed queues. Use PATCH /tables/{tableID} or PATCH /tables/bulk to attach or clear the player list that scorekeepers should pull from during setup.

Collection routeGET /tables
Record routeGET/PATCH /tables/{tableID}
Bulk assignmentPATCH /tables/bulk

Implementation notes

  • Reading a single table requires both tables.read and matches.read because the response includes this connection's scheduled matches.
  • When clearing an assignment, send null or an empty string as playerListExternalID.
  • Bulk assignment returns 207 when some tables succeed and others fail.

Endpoints

OpenAPI
GET/tables/{tableID}

Inspect one table and its managed queue

Read the table definition plus matches currently managed by this connection for that table.

tables.readmatches.read
Response

Returns the table resource and scheduled matches visible to the connection.

curl
curl https://your-domain.example/api/v1/tables/table-1 \
  -H "Authorization: Bearer osb_test_your_key_here"
JavaScript
const baseURL = "https://your-domain.example/api/v1";
const apiKey = "osb_test_your_key_here";

async function api(path, init = {}) {
  const response = await fetch(`${baseURL}${path}`, {
    ...init,
    headers: {
      "Authorization": `Bearer ${apiKey}`,
      "Content-Type": "application/json",
      "OpenScoreboard-Request-ID": "demo-request-001",
      ...(init.headers || {})
    }
  });

  const body = await response.json();
  if (!response.ok) {
    throw new Error(body.error?.message || "Request failed");
  }

  return body.data;
}

const table = await api("/tables/table-1");
console.log(table.tableID, table.scheduledMatches?.length || 0);
PATCH/tables/{tableID}

Assign a player list to one table

Attach or clear the synchronized player list used by a scoring table.

tables.writeplayer_lists.read
Response

Returns the updated table state for that assignment.

curl
curl -X PATCH https://your-domain.example/api/v1/tables/table-1 \
  -H "Authorization: Bearer osb_test_your_key_here" \
  -H "Content-Type: application/json" \
  -H "OpenScoreboard-Request-ID: demo-request-001" \
  -d '{
    "playerListExternalID": "summer-open-singles"
  }'
JavaScript
const baseURL = "https://your-domain.example/api/v1";
const apiKey = "osb_test_your_key_here";

async function api(path, init = {}) {
  const response = await fetch(`${baseURL}${path}`, {
    ...init,
    headers: {
      "Authorization": `Bearer ${apiKey}`,
      "Content-Type": "application/json",
      "OpenScoreboard-Request-ID": "demo-request-001",
      ...(init.headers || {})
    }
  });

  const body = await response.json();
  if (!response.ok) {
    throw new Error(body.error?.message || "Request failed");
  }

  return body.data;
}

await api("/tables/table-1", {
  method: "PATCH",
  body: JSON.stringify({
    playerListExternalID: "summer-open-singles"
  })
});
PATCH/tables/bulk

Assign multiple tables in one call

Apply ordered per-table player-list assignments across up to 100 tables.

tables.writeplayer_lists.read
Response

Returns per-table results and may use HTTP 207 for partial success.

curl
curl -X PATCH https://your-domain.example/api/v1/tables/bulk \
  -H "Authorization: Bearer osb_test_your_key_here" \
  -H "Content-Type: application/json" \
  -H "OpenScoreboard-Request-ID: demo-request-001" \
  -d '{
    "tables": [
      { "tableID": "table-1", "playerListExternalID": "summer-open-singles" },
      { "tableID": "table-2", "playerListExternalID": null }
    ]
  }'
JavaScript
const baseURL = "https://your-domain.example/api/v1";
const apiKey = "osb_test_your_key_here";

async function api(path, init = {}) {
  const response = await fetch(`${baseURL}${path}`, {
    ...init,
    headers: {
      "Authorization": `Bearer ${apiKey}`,
      "Content-Type": "application/json",
      "OpenScoreboard-Request-ID": "demo-request-001",
      ...(init.headers || {})
    }
  });

  const body = await response.json();
  if (!response.ok) {
    throw new Error(body.error?.message || "Request failed");
  }

  return body.data;
}

const result = await api("/tables/bulk", {
  method: "PATCH",
  body: JSON.stringify({
    tables: [
      { tableID: "table-1", playerListExternalID: "summer-open-singles" },
      { tableID: "table-2", playerListExternalID: null }
    ]
  })
});

console.log(result.succeeded, result.failed);