Docs menu

HTTP API reference

Every game-facing route the server answers, generated from its route definitions and checked against the HTTP contract tests (163 recorded requests). The game library calls these for you; use this page when you write tools, debug traffic or build a client in another language.

Authentication

  • Public key (sbox_ns_...) in x-public-key or the apiKey query parameter: game clients. Ships inside your game.
  • Player identity: x-steam-id plus an s&box auth token in x-sbox-token when the project requires player authentication.
  • Secret key (sbox_sk_...) in x-api-key or x-secret-key: editor sync, dedicated servers and management routes. Never ship it in a game build.
  • Client identity headers such as x-ns-library-version and x-ns-client-type are diagnostics, not authentication. See compatibility.

Errors use one envelope: {"ok": false, "error": {"code": "...", "message": "..."}}. Paths below use {projectId}-style placeholders; examples use the test variables (${projectId}, ${publicKey}).

Auth sessions /v3/auth-sessions

POST/v3/auth-sessions/{projectId}/create

Status codes in tests
200
Example from the contract tests (auth-sessions / create)
{
  "method": "POST",
  "path": "/v3/auth-sessions/${projectId}/create",
  "query": {
    "apiKey": "${publicKey}"
  },
  "headers": {
    "x-api-key": "${publicKey}",
    "x-public-key": "${publicKey}",
    "x-steam-id": "${steamId}",
    "x-sbox-token": "parity-placeholder-token"
  },
  "body": {
    "steamId": "${steamId}"
  }
}

Expected response status 200.

POST/v3/auth-sessions/{projectId}/reauth

Status codes in tests
200
Example from the contract tests (auth-sessions / reauth)
{
  "method": "POST",
  "path": "/v3/auth-sessions/${projectId}/reauth",
  "query": {
    "apiKey": "${publicKey}"
  },
  "headers": {
    "x-api-key": "${publicKey}",
    "x-auth-session": "not-a-session-token"
  },
  "body": {}
}

Expected response status 200.

POST/v3/auth-sessions/{projectId}/refresh

Status codes in tests
200
Example from the contract tests (auth-sessions / refresh-no-token)
{
  "method": "POST",
  "path": "/v3/auth-sessions/${projectId}/refresh",
  "query": {
    "apiKey": "${publicKey}"
  },
  "headers": {
    "x-api-key": "${publicKey}"
  },
  "body": {}
}

Expected response status 200.

POST/v3/auth-sessions/{projectId}/revoke

Status codes in tests
200
Example from the contract tests (auth-sessions / revoke)
{
  "method": "POST",
  "path": "/v3/auth-sessions/${projectId}/revoke",
  "query": {
    "apiKey": "${publicKey}"
  },
  "headers": {
    "x-api-key": "${publicKey}"
  },
  "body": {
    "sessionToken": "not-a-session-token"
  }
}

Expected response status 200.

Server endpoints /v3/endpoints

POST/v3/endpoints/{projectId}

Status codes in tests
200 400
Example from the contract tests (endpoints-get-and-routing / post-body-slug)
{
  "method": "POST",
  "path": "/v3/endpoints/${projectId}",
  "query": {
    "apiKey": "${publicKey}"
  },
  "headers": {
    "x-public-key": "${publicKey}",
    "x-steam-id": "${steamId}",
    "x-sbox-token": "parity-placeholder-token",
    "x-ns-client-type": "game"
  },
  "body": {
    "endpoint": "load-profile",
    "security": {
      "configVersion": "",
      "clientMode": "legacy",
      "authSessions": "disabled",
      "encryptedRequests": "disabled",
      "revisionId": 0,
      "revisionOutdated": false
    }
  }
}

Expected response status 200.

GET/v3/endpoints/{projectId}/{endpointSlug}

Status codes in tests
200 404
Example from the contract tests (endpoints-get-and-routing / get-market)
{
  "method": "GET",
  "path": "/v3/endpoints/${projectId}/market-listings",
  "query": {
    "apiKey": "${publicKey}"
  },
  "headers": {
    "x-public-key": "${publicKey}",
    "x-steam-id": "${steamId}",
    "x-sbox-token": "parity-placeholder-token",
    "x-ns-client-type": "game"
  }
}

Expected response status 200.

POST/v3/endpoints/{projectId}/{endpointSlug}

Status codes in tests
200 400 401 404 409 413
Example from the contract tests (endpoints-player-flow / load-empty)
{
  "method": "POST",
  "path": "/v3/endpoints/${projectId}/load-profile",
  "query": {
    "apiKey": "${publicKey}"
  },
  "headers": {
    "x-public-key": "${publicKey}",
    "x-steam-id": "${steamId}",
    "x-sbox-token": "parity-placeholder-token",
    "x-ns-client-type": "game"
  },
  "body": {
    "security": {
      "configVersion": "",
      "clientMode": "legacy",
      "authSessions": "disabled",
      "encryptedRequests": "disabled",
      "revisionId": 0,
      "revisionOutdated": false
    },
    "_endpointSlug": "load-profile"
  }
}

Expected response status 200.

Management (secret key) /v3/manage

GET/v3/manage/{projectId}/{**path}

Status codes in tests
200 401
Library call
Editor/SyncToolApi.cs ValidateCredentials, Code/Auth/NetworkStorageDedicatedServerSecretValidation.cs
dashboard/CI management API (docs 18-rest-api-reference)
Editor/SyncToolApi.cs (Request: x-api-key secret + x-public-key) PreflightSync/PushSync, Editor/SyncToolSourceFiles.cs payload shape
Editor/sync.py (api_request: x-api-key secret + x-public-key, JSON body), Editor/SyncToolApi.cs PatchEndpoint/PatchCollection/PatchWorkflow
management API (docs 06-rate-limits)
management API (Code/Storage/NetworkStorageQueries.cs consumes them)
Editor/SyncToolApi.cs (Request: x-api-key secret + x-public-key) SyncPackageInfo/GetGamePackage, Code/Core/NetworkStorageRevisionInit.cs
Editor/SyncToolApi.cs (Request: x-api-key secret + x-public-key) AutoTest/RunTest/GetTests/UpgradeSource/GetSyncJobStatus
Editor/SyncToolApi.cs, Code/Core/NetworkStorageHttp.cs
docs 09-error-codes
Example from the contract tests (manage-validate / validate-both-keys)
{
  "method": "GET",
  "path": "/v3/manage/${projectId}/validate",
  "headers": {
    "x-api-key": "${secretKey}",
    "x-public-key": "${publicKey}"
  }
}

Expected response status 200.

POST/v3/manage/{projectId}/{**path}

Status codes in tests
404
Example from the contract tests (errors-invalid-input / manage-unknown-mutation)
{
  "method": "POST",
  "path": "/v3/manage/${projectId}/does-not-exist",
  "headers": {
    "x-api-key": "${secretKey}",
    "x-public-key": "${publicKey}",
    "Content-Type": "application/json"
  },
  "body": {}
}

Expected response status 404.

POST/v3/manage/{projectId}/auto-test

Status codes in tests
200
Library call
Editor/SyncToolApi.cs (Request: x-api-key secret + x-public-key) AutoTest/RunTest/GetTests/UpgradeSource/GetSyncJobStatus
Example from the contract tests (manage-tests-and-tools / auto-test-one)
{
  "method": "POST",
  "path": "/v3/manage/${projectId}/auto-test",
  "headers": {
    "x-api-key": "${secretKey}",
    "x-public-key": "${publicKey}",
    "Content-Type": "application/json",
    "x-ns-publish-target": "live"
  },
  "body": {
    "slug": "mine-ore"
  }
}

Expected response status 200.

PATCH/v3/manage/{projectId}/collections

Status codes in tests
200
Library call
Editor/sync.py (api_request: x-api-key secret + x-public-key, JSON body), Editor/SyncToolApi.cs PatchEndpoint/PatchCollection/PatchWorkflow
Example from the contract tests (manage-resource-crud / patch-collection)
{
  "method": "PATCH",
  "path": "/v3/manage/${projectId}/collections",
  "headers": {
    "x-api-key": "${secretKey}",
    "x-public-key": "${publicKey}",
    "Content-Type": "application/json"
  },
  "body": {
    "id": "inventory",
    "name": "inventory",
    "description": "Per-player item stacks.",
    "collectionType": "per-steamid",
    "accessMode": "public",
    "maxRecords": 1,
    "allowRecordDelete": false,
    "requireSaveVersion": false,
    "rateLimitAction": "reject",
    "rateLimits": {
      "mode": "none"
    },
    "schema": {
      "items": {
        "type": "array",
        "default": [],
        "items": {
          "type": "object"
        }
      }
    }
  }
}

Expected response status 200.

POST/v3/manage/{projectId}/collections

Contract tests
Not covered by the HTTP contract tests yet.

PUT/v3/manage/{projectId}/collections

Status codes in tests
200 400 401
Library call
Editor/sync.py (api_request: x-api-key secret + x-public-key, JSON body), Editor/SyncToolApi.cs PatchEndpoint/PatchCollection/PatchWorkflow
Editor/SyncToolApi.cs, Code/Core/NetworkStorageHttp.cs
Example from the contract tests (manage-resource-crud / put-collections)
{
  "method": "PUT",
  "path": "/v3/manage/${projectId}/collections",
  "headers": {
    "x-api-key": "${secretKey}",
    "x-public-key": "${publicKey}",
    "Content-Type": "application/json"
  },
  "body": [
    {
      "id": "inventory",
      "name": "inventory",
      "description": "Per-player item stacks.",
      "collectionType": "per-steamid",
      "accessMode": "public",
      "maxRecords": 1,
      "allowRecordDelete": false,
      "requireSaveVersion": false,
      "rateLimitAction": "reject",
      "rateLimits": {
        "mode": "none"
      },
      "schema": {
        "items": {
          "type": "array",
          "default": [],
          "items": {
            "type": "object"
          }
        }
      }
    }
  ]
}

Expected response status 200.

DELETE/v3/manage/{projectId}/collections/{collectionId}

Status codes in tests
200
Library call
Editor/sync.py (api_request: x-api-key secret + x-public-key, JSON body), Editor/SyncToolApi.cs PatchEndpoint/PatchCollection/PatchWorkflow
Example from the contract tests (manage-resource-crud / delete-collection)
{
  "method": "DELETE",
  "path": "/v3/manage/${projectId}/collections/inventory",
  "headers": {
    "x-api-key": "${secretKey}",
    "x-public-key": "${publicKey}"
  }
}

Expected response status 200.

PATCH/v3/manage/{projectId}/endpoints

Status codes in tests
200
Library call
Editor/sync.py (api_request: x-api-key secret + x-public-key, JSON body), Editor/SyncToolApi.cs PatchEndpoint/PatchCollection/PatchWorkflow
Example from the contract tests (manage-resource-crud / patch-endpoint)
{
  "method": "PATCH",
  "path": "/v3/manage/${projectId}/endpoints",
  "headers": {
    "x-api-key": "${secretKey}",
    "x-public-key": "${publicKey}",
    "Content-Type": "application/json"
  },
  "body": {
    "id": "ping",
    "slug": "ping",
    "name": "ping",
    "description": "Health ping endpoint.",
    "enabled": true,
    "method": "POST",
    "input": {
      "type": "object",
      "properties": {}
    },
    "steps": [],
    "response": {
      "status": 200,
      "body": {
        "ok": true,
        "pong": true
      }
    }
  }
}

Expected response status 200.

POST/v3/manage/{projectId}/endpoints

Contract tests
Not covered by the HTTP contract tests yet.

PUT/v3/manage/{projectId}/endpoints

Status codes in tests
200 400
Library call
Editor/sync.py (api_request: x-api-key secret + x-public-key, JSON body), Editor/SyncToolApi.cs PatchEndpoint/PatchCollection/PatchWorkflow
Example from the contract tests (manage-resource-crud / put-endpoints)
{
  "method": "PUT",
  "path": "/v3/manage/${projectId}/endpoints",
  "headers": {
    "x-api-key": "${secretKey}",
    "x-public-key": "${publicKey}",
    "Content-Type": "application/json"
  },
  "body": [
    {
      "id": "ping",
      "slug": "ping",
      "name": "ping",
      "description": "Health ping endpoint.",
      "enabled": true,
      "method": "POST",
      "input": {
        "type": "object",
        "properties": {}
      },
      "steps": [],
      "response": {
        "status": 200,
        "body": {
          "ok": true,
          "pong": true
        }
      }
    }
  ]
}

Expected response status 200.

DELETE/v3/manage/{projectId}/endpoints/{endpointId}

Status codes in tests
200
Library call
Editor/sync.py (api_request: x-api-key secret + x-public-key, JSON body), Editor/SyncToolApi.cs PatchEndpoint/PatchCollection/PatchWorkflow
Example from the contract tests (manage-resource-crud / delete-endpoint)
{
  "method": "DELETE",
  "path": "/v3/manage/${projectId}/endpoints/ping",
  "headers": {
    "x-api-key": "${secretKey}",
    "x-public-key": "${publicKey}"
  }
}

Expected response status 200.

DELETE/v3/manage/{projectId}/game-values

Contract tests
Not covered by the HTTP contract tests yet.

POST/v3/manage/{projectId}/game-values

Contract tests
Not covered by the HTTP contract tests yet.

PUT/v3/manage/{projectId}/game-values

Status codes in tests
200
Library call
dashboard/CI management API (docs 18-rest-api-reference)
Example from the contract tests (manage-game-values / put)
{
  "method": "PUT",
  "path": "/v3/manage/${projectId}/game-values",
  "headers": {
    "x-api-key": "${secretKey}",
    "x-public-key": "${publicKey}",
    "Content-Type": "application/json"
  },
  "body": {
    "items": [
      {
        "id": "economy",
        "type": "group",
        "name": "Economy",
        "description": "Economy tuning",
        "entries": {
          "startingGold": 100,
          "oreValue": 3
        }
      },
      {
        "id": "upgrades",
        "type": "table",
        "name": "Upgrades",
        "columns": [
          {
            "key": "id",
            "type": "string"
          },
          {
            "key": "baseCost",
            "type": "number"
          },
          {
            "key": "costGrowth",
            "type": "number"
          }
        ],
        "rows": [
          {
            "id": "pickaxe",
            "baseCost": 10,
            "costGrowth": 1.5
          },
          {
            "id": "drill",
            "baseCost": 250,
            "costGrowth": 2
          }
        ]
      }
    ]
  }
}

Expected response status 200.

DELETE/v3/manage/{projectId}/keys

Contract tests
Not covered by the HTTP contract tests yet.

POST/v3/manage/{projectId}/package-sync

Status codes in tests
200
Library call
Editor/SyncToolApi.cs (Request: x-api-key secret + x-public-key) SyncPackageInfo/GetGamePackage, Code/Core/NetworkStorageRevisionInit.cs
Example from the contract tests (manage-package-and-revision / package-sync)
{
  "method": "POST",
  "path": "/v3/manage/${projectId}/package-sync",
  "headers": {
    "x-api-key": "${secretKey}",
    "x-public-key": "${publicKey}",
    "Content-Type": "application/json"
  },
  "body": {
    "packageId": "parity.testgame",
    "packageIdent": "parity.testgame",
    "packageTitle": "Parity Test Game",
    "orgIdent": "parity",
    "packageType": "game",
    "runtimeClientType": "editor",
    "isEditorContext": true,
    "isPublishedGameBundle": false,
    "currentRevisionId": 41,
    "latestRevisionId": 42,
    "publishStatus": "published",
    "rawPackage": {},
    "rawRevision": {},
    "rawBundle": {}
  }
}

Expected response status 200.

POST/v3/manage/{projectId}/queries

Status codes in tests
200
Library call
management API (Code/Storage/NetworkStorageQueries.cs consumes them)
Example from the contract tests (manage-queries / create-leaderboard)
{
  "method": "POST",
  "path": "/v3/manage/${projectId}/queries",
  "headers": {
    "x-api-key": "${secretKey}",
    "x-public-key": "${publicKey}",
    "Content-Type": "application/json"
  },
  "body": [
    {
      "id": "top_miners",
      "name": "top_miners",
      "type": "leaderboard",
      "requiresSecretKey": false,
      "sources": [
        {
          "collectionId": "players"
        }
      ],
      "config": {
        "field": "ores.stone",
        "order": "desc",
        "limit": 10
      }
    }
  ]
}

Expected response status 200.

DELETE/v3/manage/{projectId}/queries/{queryId}

Status codes in tests
200
Library call
management API (Code/Storage/NetworkStorageQueries.cs consumes them)
Example from the contract tests (manage-queries / delete-scratch)
{
  "method": "DELETE",
  "path": "/v3/manage/${projectId}/queries/scratch_query",
  "headers": {
    "x-api-key": "${secretKey}",
    "x-public-key": "${publicKey}"
  }
}

Expected response status 200.

DELETE/v3/manage/{projectId}/rate-limit-rules

Contract tests
Not covered by the HTTP contract tests yet.

POST/v3/manage/{projectId}/rate-limit-rules

Contract tests
Not covered by the HTTP contract tests yet.

PUT/v3/manage/{projectId}/rate-limit-rules

Status codes in tests
200
Library call
management API (docs 06-rate-limits)
Example from the contract tests (manage-rate-limit-rules / put)
{
  "method": "PUT",
  "path": "/v3/manage/${projectId}/rate-limit-rules",
  "headers": {
    "x-api-key": "${secretKey}",
    "x-public-key": "${publicKey}",
    "Content-Type": "application/json"
  },
  "body": {
    "rules": [
      {
        "name": "ore_minute_cap",
        "collection": "players",
        "field": "ores.stone",
        "scope": "per_player",
        "window": "perMinute",
        "limit": 1000,
        "action": "reject"
      },
      {
        "name": "gold_daily_flag",
        "collection": "players",
        "field": "gold",
        "scope": "per_player",
        "window": "perDay",
        "limit": 1000000,
        "action": "flag"
      }
    ]
  }
}

Expected response status 200.

POST/v3/manage/{projectId}/revision-init

Status codes in tests
200
Library call
Editor/SyncToolApi.cs (Request: x-api-key secret + x-public-key) SyncPackageInfo/GetGamePackage, Code/Core/NetworkStorageRevisionInit.cs
Example from the contract tests (manage-package-and-revision / revision-init)
{
  "method": "POST",
  "path": "/v3/manage/${projectId}/revision-init",
  "query": {
    "apiKey": "${publicKey}"
  },
  "headers": {
    "x-public-key": "${publicKey}",
    "x-ns-revision-id": "42",
    "x-ns-client-type": "game"
  },
  "body": {
    "projectId": "${projectId}",
    "clientType": "game",
    "networkStorageVersion": "1.0",
    "isPublishedGameBundle": true,
    "packageIdent": "parity.testgame",
    "revisionId": 42
  }
}

Expected response status 200.

POST/v3/manage/{projectId}/run-tests

Contract tests
Not covered by the HTTP contract tests yet.

PUT/v3/manage/{projectId}/settings

Contract tests
Not covered by the HTTP contract tests yet.

POST/v3/manage/{projectId}/source-upgrade

Status codes in tests
200
Library call
Editor/SyncToolApi.cs (Request: x-api-key secret + x-public-key) AutoTest/RunTest/GetTests/UpgradeSource/GetSyncJobStatus
Example from the contract tests (manage-tests-and-tools / source-upgrade)
{
  "method": "POST",
  "path": "/v3/manage/${projectId}/source-upgrade",
  "headers": {
    "x-api-key": "${secretKey}",
    "x-public-key": "${publicKey}",
    "Content-Type": "application/json"
  },
  "body": {
    "kind": "endpoint",
    "id": "mine-ore",
    "sourceFormat": "yaml",
    "sourcePath": "mine-ore.endpoint.yml",
    "sourceText": "sourceVersion: 1\nkind: endpoint\nid: mine-ore\nname: Mine Ore\ndescription: Adds ore after validating the amount.\nexposure: public\nmethod: POST\ninput:\n  type: object\n  properties:\n    amount:\n      type: number\n  required: [ amount ]\nsteps:\n  - id: player\n    type: read\n    collection: players\n    key: \"{{steamId}}\"\n  - id: positive_amount\n    type: condition\n    check:\n      field: \"{{input.amount}}\"\n      op: \">\"\n      value: 0\n    routes:\n      false:\n        action: reject\n        status: 400\n        error: INVALID_AMOUNT\n        message: Amount must be positive.\n  - id: apply\n    type: write\n    collection: players\n    key: \"{{steamId}}\"\n    ops:\n      - op: inc\n        path: ores.stone\n        value: \"{{input.amount}}\"\nresponse:\n  status: 200\n  body:\n    ok: true\n    mined: \"{{input.amount}}\"\n"
  }
}

Expected response status 200.

POST/v3/manage/{projectId}/suggest-tests

Contract tests
Not covered by the HTTP contract tests yet.

PUT/v3/manage/{projectId}/sync

Status codes in tests
200 400
Library call
Editor/SyncToolApi.cs (Request: x-api-key secret + x-public-key) PreflightSync/PushSync, Editor/SyncToolSourceFiles.cs payload shape
Example from the contract tests (manage-push-all / push)
{
  "method": "PUT",
  "path": "/v3/manage/${projectId}/sync",
  "headers": {
    "x-api-key": "${secretKey}",
    "x-public-key": "${publicKey}",
    "Content-Type": "application/json"
  },
  "body": {
    "endpoints": [
      {
        "kind": "endpoint",
        "id": "load-profile",
        "authoringMode": "source",
        "sourceFormat": "yaml",
        "sourcePath": "load-profile.endpoint.yml",
        "sourceText": "sourceVersion: 1\nkind: endpoint\nid: load-profile\nname: Load Profile\ndescription: Return the caller's players record.\nexposure: public\nmethod: POST\ninput:\n  type: object\n  properties: {}\nsteps:\n  - id: profile\n    type: read\n    collection: players\n    key: \"{{steamId}}\"\nresponse:\n  status: 200\n  body:\n    ok: true\n    profile: \"{{profile}}\"\n"
      },
      {
        "kind": "endpoint",
        "id": "save-profile",
        "authoringMode": "source",
        "sourceFormat": "yaml",
        "sourcePath": "save-profile.endpoint.yml",
        "sourceText": "sourceVersion: 1\nkind: endpoint\nid: save-profile\nname: Save Profile\ndescription: Save non-economic profile state.\nexposure: public\nmethod: POST\ninput:\n  type: object\n  properties:\n    playerName:\n      type: string\n  required: [ playerName ]\nsteps:\n  - id: save\n    type: write\n    collection: players\n    key: \"{{steamId}}\"\n    ops:\n      - op: set\n        path: playerName\n        value: \"{{input.playerName}}\"\nresponse:\n  status: 200\n  body:\n    ok: true\n"
      },
      {
        "kind": "endpoint",
        "id": "mine-ore",
        "authoringMode": "source",
        "sourceFormat": "yaml",
        "sourcePath": "mine-ore.endpoint.yml",
        "sourceText": "sourceVersion: 1\nkind: endpoint\nid: mine-ore\nname: Mine Ore\ndescription: Adds ore after validating the amount.\nexposure: public\nmethod: POST\ninput:\n  type: object\n  properties:\n    amount:\n      type: number\n  required: [ amount ]\nsteps:\n  - id: player\n    type: read\n    collection: players\n    key: \"{{steamId}}\"\n  - id: positive_amount\n    type: condition\n    check:\n      field: \"{{input.amount}}\"\n      op: \">\"\n      value: 0\n    routes:\n      false:\n        action: reject\n        status: 400\n        error: INVALID_AMOUNT\n        message: Amount must be positive.\n  - id: apply\n    type: write\n    collection: players\n    key: \"{{steamId}}\"\n    ops:\n      - op: inc\n        path: ores.stone\n        value: \"{{input.amount}}\"\nresponse:\n  status: 200\n  body:\n    ok: true\n    mined: \"{{input.amount}}\"\n"
      },
      {
        "kind": "endpoint",
        "id": "buy-upgrade",
        "authoringMode": "source",
        "sourceFormat": "yaml",
        "sourcePath": "buy-upgrade.endpoint.yml",
        "sourceText": "sourceVersion: 1\nkind: endpoint\nid: buy-upgrade\nname: Buy Upgrade\ndescription: Workflow-backed purchase priced from the upgrades game-values table.\nexposure: public\nmethod: POST\ninput:\n  type: object\n  properties:\n    upgradeId:\n      type: string\n  required: [ upgradeId ]\nsteps:\n  - id: player\n    type: read\n    collection: players\n    key: \"{{steamId}}\"\n  - id: upgrade\n    type: lookup\n    source: values\n    table: upgrades\n    required: true\n    onMissing:\n      status: 400\n      errorCode: UNKNOWN_UPGRADE\n      message: Unknown upgrade.\n    where:\n      field: id\n      op: ==\n      value: \"{{input.upgradeId}}\"\n  - id: pricing\n    type: workflow\n    workflow: scaled-cost\n    params:\n      baseCost: \"{{upgrade.baseCost}}\"\n      costGrowth: \"{{upgrade.costGrowth}}\"\n      currentValue: \"{{player.level}}\"\n  - id: afford\n    type: workflow\n    workflow: check-currency\n    params:\n      balance: \"{{player.gold}}\"\n      cost: \"{{pricing.cost}}\"\n  - id: charge\n    type: write\n    collection: players\n    key: \"{{steamId}}\"\n    ops:\n      - op: inc\n        path: gold\n        value: \"{{pricing.negCost}}\"\n      - op: set\n        path: level\n        value: \"{{pricing.nextValue}}\"\nresponse:\n  status: 200\n  body:\n    ok: true\n    cost: \"{{pricing.cost}}\"\n    level: \"{{pricing.nextValue}}\"\n"
      },
      {
        "kind": "endpoint",
        "id": "market-listings",
        "authoringMode": "source",
        "sourceFormat": "yaml",
        "sourcePath": "market-listings.endpoint.yml",
        "sourceText": "sourceVersion: 1\nkind: endpoint\nid: market-listings\nname: Market Listings\ndescription: Static read-only listing endpoint (callable by GET).\nexposure: public\nmethod: GET\nsteps: []\nresponse:\n  status: 200\n  body:\n    ok: true\n    listings: []\n"
      },
      {
        "kind": "endpoint",
        "id": "grant-gold",
        "authoringMode": "source",
        "sourceFormat": "yaml",
        "sourcePath": "grant-gold.endpoint.yml",
        "sourceText": "sourceVersion: 1\nkind: endpoint\nid: grant-gold\nname: Grant Gold\ndescription: Dedicated-server-only reward grant.\nexposure: public\nrequiresSecretKey: true\nmethod: POST\ninput:\n  type: object\n  properties:\n    amount:\n      type: number\n  required: [ amount ]\nsteps:\n  - id: grant\n    type: write\n    collection: players\n    key: \"{{steamId}}\"\n    ops:\n      - op: inc\n        path: gold\n        value: \"{{input.amount}}\"\nresponse:\n  status: 200\n  body:\n    ok: true\n    granted: \"{{input.amount}}\"\n"
      }
    ],
    "collections": [
      {
        "kind": "collection",
        "id": "players",
        "authoringMode": "source",
        "sourceFormat": "yaml",
        "sourcePath": "players.collection.yml",
        "sourceText": "sourceVersion: 1\nkind: collection\nid: players\nname: players\ndescription: Per-player profile and economy state.\ndefinition:\n  collectionType: per-steamid\n  accessMode: public\n  maxRecords: 1\n  allowRecordDelete: true\n  requireSaveVersion: false\n  rateLimitAction: reject\n  rateLimits:\n    mode: none\n  schema:\n    playerName:\n      type: string\n      default: \"\"\n    gold:\n      type: number\n      default: 100\n      _ledger: true\n    level:\n      type: number\n      default: 0\n    ores:\n      type: object\n      default:\n        stone: 0\n      properties:\n        stone:\n          type: number\n"
      },
      {
        "kind": "collection",
        "id": "save_slots",
        "authoringMode": "source",
        "sourceFormat": "yaml",
        "sourcePath": "save_slots.collection.yml",
        "sourceText": "sourceVersion: 1\nkind: collection\nid: save_slots\nname: save_slots\ndescription: Up to three save files per player.\ndefinition:\n  collectionType: per-steamid\n  accessMode: public\n  maxRecords: 3\n  allowRecordDelete: true\n  schema:\n    slotName:\n      type: string\n      default: \"\"\n    playtimeSeconds:\n      type: number\n      default: 0\n"
      },
      {
        "kind": "collection",
        "id": "leaderboard_global",
        "authoringMode": "source",
        "sourceFormat": "yaml",
        "sourcePath": "leaderboard_global.collection.yml",
        "sourceText": "sourceVersion: 1\nkind: collection\nid: leaderboard_global\nname: leaderboard_global\ndescription: Shared append-only run log.\ndefinition:\n  collectionType: global\n  accessMode: public\n  allowRecordDelete: false\n  schema:\n    score:\n      type: number\n    playerName:\n      type: string\n"
      }
    ],
    "workflows": [
      {
        "kind": "workflow",
        "id": "scaled-cost",
        "authoringMode": "source",
        "sourceFormat": "yaml",
        "sourcePath": "scaled-cost.workflow.yml",
        "sourceText": "sourceVersion: 1\nkind: workflow\nid: scaled-cost\nname: Scaled Cost\ndescription: Compute an exponential purchase cost for the next level.\ndefinition:\n  params:\n    baseCost:\n      type: number\n    costGrowth:\n      type: number\n    currentValue:\n      type: number\n  steps:\n    - id: current_value\n      type: transform\n      expression: \"max(0, {{currentValue}})\"\n    - id: cost\n      type: transform\n      expression: \"ceil({{baseCost}} * pow({{costGrowth}}, {{current_value}}))\"\n    - id: neg_cost\n      type: transform\n      expression: \"0 - {{cost}}\"\n    - id: next_value\n      type: transform\n      expression: \"{{current_value}} + 1\"\n  returns:\n    cost: \"{{cost}}\"\n    negCost: \"{{neg_cost}}\"\n    nextValue: \"{{next_value}}\"\n"
      },
      {
        "kind": "workflow",
        "id": "check-currency",
        "authoringMode": "source",
        "sourceFormat": "yaml",
        "sourcePath": "check-currency.workflow.yml",
        "sourceText": "sourceVersion: 1\nkind: workflow\nid: check-currency\nname: Check Currency\ndescription: Validate that a player has enough currency for a cost.\ndefinition:\n  params:\n    balance:\n      type: number\n    cost:\n      type: number\n  steps:\n    - id: has_currency\n      type: condition\n      check:\n        field: \"{{balance}}\"\n        op: \">=\"\n        value: \"{{cost}}\"\n      onFail:\n        status: 409\n        error: INSUFFICIENT_CURRENCY\n        message: Not enough currency.\n  returns:\n    ok: true\n"
      }
    ]
  }
}

Expected response status 200.

POST/v3/manage/{projectId}/sync/preflight

Status codes in tests
200 400
Library call
Editor/SyncToolApi.cs (Request: x-api-key secret + x-public-key) PreflightSync/PushSync, Editor/SyncToolSourceFiles.cs payload shape
Code/Storage/NetworkStorageCollections.cs EscapeRouteSegment
Example from the contract tests (manage-push-all / preflight)
{
  "method": "POST",
  "path": "/v3/manage/${projectId}/sync/preflight",
  "headers": {
    "x-api-key": "${secretKey}",
    "x-public-key": "${publicKey}",
    "Content-Type": "application/json"
  },
  "body": {
    "endpoints": [
      {
        "kind": "endpoint",
        "id": "load-profile",
        "authoringMode": "source",
        "sourceFormat": "yaml",
        "sourcePath": "load-profile.endpoint.yml",
        "sourceText": "sourceVersion: 1\nkind: endpoint\nid: load-profile\nname: Load Profile\ndescription: Return the caller's players record.\nexposure: public\nmethod: POST\ninput:\n  type: object\n  properties: {}\nsteps:\n  - id: profile\n    type: read\n    collection: players\n    key: \"{{steamId}}\"\nresponse:\n  status: 200\n  body:\n    ok: true\n    profile: \"{{profile}}\"\n"
      },
      {
        "kind": "endpoint",
        "id": "save-profile",
        "authoringMode": "source",
        "sourceFormat": "yaml",
        "sourcePath": "save-profile.endpoint.yml",
        "sourceText": "sourceVersion: 1\nkind: endpoint\nid: save-profile\nname: Save Profile\ndescription: Save non-economic profile state.\nexposure: public\nmethod: POST\ninput:\n  type: object\n  properties:\n    playerName:\n      type: string\n  required: [ playerName ]\nsteps:\n  - id: save\n    type: write\n    collection: players\n    key: \"{{steamId}}\"\n    ops:\n      - op: set\n        path: playerName\n        value: \"{{input.playerName}}\"\nresponse:\n  status: 200\n  body:\n    ok: true\n"
      },
      {
        "kind": "endpoint",
        "id": "mine-ore",
        "authoringMode": "source",
        "sourceFormat": "yaml",
        "sourcePath": "mine-ore.endpoint.yml",
        "sourceText": "sourceVersion: 1\nkind: endpoint\nid: mine-ore\nname: Mine Ore\ndescription: Adds ore after validating the amount.\nexposure: public\nmethod: POST\ninput:\n  type: object\n  properties:\n    amount:\n      type: number\n  required: [ amount ]\nsteps:\n  - id: player\n    type: read\n    collection: players\n    key: \"{{steamId}}\"\n  - id: positive_amount\n    type: condition\n    check:\n      field: \"{{input.amount}}\"\n      op: \">\"\n      value: 0\n    routes:\n      false:\n        action: reject\n        status: 400\n        error: INVALID_AMOUNT\n        message: Amount must be positive.\n  - id: apply\n    type: write\n    collection: players\n    key: \"{{steamId}}\"\n    ops:\n      - op: inc\n        path: ores.stone\n        value: \"{{input.amount}}\"\nresponse:\n  status: 200\n  body:\n    ok: true\n    mined: \"{{input.amount}}\"\n"
      },
      {
        "kind": "endpoint",
        "id": "buy-upgrade",
        "authoringMode": "source",
        "sourceFormat": "yaml",
        "sourcePath": "buy-upgrade.endpoint.yml",
        "sourceText": "sourceVersion: 1\nkind: endpoint\nid: buy-upgrade\nname: Buy Upgrade\ndescription: Workflow-backed purchase priced from the upgrades game-values table.\nexposure: public\nmethod: POST\ninput:\n  type: object\n  properties:\n    upgradeId:\n      type: string\n  required: [ upgradeId ]\nsteps:\n  - id: player\n    type: read\n    collection: players\n    key: \"{{steamId}}\"\n  - id: upgrade\n    type: lookup\n    source: values\n    table: upgrades\n    required: true\n    onMissing:\n      status: 400\n      errorCode: UNKNOWN_UPGRADE\n      message: Unknown upgrade.\n    where:\n      field: id\n      op: ==\n      value: \"{{input.upgradeId}}\"\n  - id: pricing\n    type: workflow\n    workflow: scaled-cost\n    params:\n      baseCost: \"{{upgrade.baseCost}}\"\n      costGrowth: \"{{upgrade.costGrowth}}\"\n      currentValue: \"{{player.level}}\"\n  - id: afford\n    type: workflow\n    workflow: check-currency\n    params:\n      balance: \"{{player.gold}}\"\n      cost: \"{{pricing.cost}}\"\n  - id: charge\n    type: write\n    collection: players\n    key: \"{{steamId}}\"\n    ops:\n      - op: inc\n        path: gold\n        value: \"{{pricing.negCost}}\"\n      - op: set\n        path: level\n        value: \"{{pricing.nextValue}}\"\nresponse:\n  status: 200\n  body:\n    ok: true\n    cost: \"{{pricing.cost}}\"\n    level: \"{{pricing.nextValue}}\"\n"
      },
      {
        "kind": "endpoint",
        "id": "market-listings",
        "authoringMode": "source",
        "sourceFormat": "yaml",
        "sourcePath": "market-listings.endpoint.yml",
        "sourceText": "sourceVersion: 1\nkind: endpoint\nid: market-listings\nname: Market Listings\ndescription: Static read-only listing endpoint (callable by GET).\nexposure: public\nmethod: GET\nsteps: []\nresponse:\n  status: 200\n  body:\n    ok: true\n    listings: []\n"
      },
      {
        "kind": "endpoint",
        "id": "grant-gold",
        "authoringMode": "source",
        "sourceFormat": "yaml",
        "sourcePath": "grant-gold.endpoint.yml",
        "sourceText": "sourceVersion: 1\nkind: endpoint\nid: grant-gold\nname: Grant Gold\ndescription: Dedicated-server-only reward grant.\nexposure: public\nrequiresSecretKey: true\nmethod: POST\ninput:\n  type: object\n  properties:\n    amount:\n      type: number\n  required: [ amount ]\nsteps:\n  - id: grant\n    type: write\n    collection: players\n    key: \"{{steamId}}\"\n    ops:\n      - op: inc\n        path: gold\n        value: \"{{input.amount}}\"\nresponse:\n  status: 200\n  body:\n    ok: true\n    granted: \"{{input.amount}}\"\n"
      }
    ],
    "collections": [
      {
        "kind": "collection",
        "id": "players",
        "authoringMode": "source",
        "sourceFormat": "yaml",
        "sourcePath": "players.collection.yml",
        "sourceText": "sourceVersion: 1\nkind: collection\nid: players\nname: players\ndescription: Per-player profile and economy state.\ndefinition:\n  collectionType: per-steamid\n  accessMode: public\n  maxRecords: 1\n  allowRecordDelete: true\n  requireSaveVersion: false\n  rateLimitAction: reject\n  rateLimits:\n    mode: none\n  schema:\n    playerName:\n      type: string\n      default: \"\"\n    gold:\n      type: number\n      default: 100\n      _ledger: true\n    level:\n      type: number\n      default: 0\n    ores:\n      type: object\n      default:\n        stone: 0\n      properties:\n        stone:\n          type: number\n"
      },
      {
        "kind": "collection",
        "id": "save_slots",
        "authoringMode": "source",
        "sourceFormat": "yaml",
        "sourcePath": "save_slots.collection.yml",
        "sourceText": "sourceVersion: 1\nkind: collection\nid: save_slots\nname: save_slots\ndescription: Up to three save files per player.\ndefinition:\n  collectionType: per-steamid\n  accessMode: public\n  maxRecords: 3\n  allowRecordDelete: true\n  schema:\n    slotName:\n      type: string\n      default: \"\"\n    playtimeSeconds:\n      type: number\n      default: 0\n"
      },
      {
        "kind": "collection",
        "id": "leaderboard_global",
        "authoringMode": "source",
        "sourceFormat": "yaml",
        "sourcePath": "leaderboard_global.collection.yml",
        "sourceText": "sourceVersion: 1\nkind: collection\nid: leaderboard_global\nname: leaderboard_global\ndescription: Shared append-only run log.\ndefinition:\n  collectionType: global\n  accessMode: public\n  allowRecordDelete: false\n  schema:\n    score:\n      type: number\n    playerName:\n      type: string\n"
      }
    ],
    "workflows": [
      {
        "kind": "workflow",
        "id": "scaled-cost",
        "authoringMode": "source",
        "sourceFormat": "yaml",
        "sourcePath": "scaled-cost.workflow.yml",
        "sourceText": "sourceVersion: 1\nkind: workflow\nid: scaled-cost\nname: Scaled Cost\ndescription: Compute an exponential purchase cost for the next level.\ndefinition:\n  params:\n    baseCost:\n      type: number\n    costGrowth:\n      type: number\n    currentValue:\n      type: number\n  steps:\n    - id: current_value\n      type: transform\n      expression: \"max(0, {{currentValue}})\"\n    - id: cost\n      type: transform\n      expression: \"ceil({{baseCost}} * pow({{costGrowth}}, {{current_value}}))\"\n    - id: neg_cost\n      type: transform\n      expression: \"0 - {{cost}}\"\n    - id: next_value\n      type: transform\n      expression: \"{{current_value}} + 1\"\n  returns:\n    cost: \"{{cost}}\"\n    negCost: \"{{neg_cost}}\"\n    nextValue: \"{{next_value}}\"\n"
      },
      {
        "kind": "workflow",
        "id": "check-currency",
        "authoringMode": "source",
        "sourceFormat": "yaml",
        "sourcePath": "check-currency.workflow.yml",
        "sourceText": "sourceVersion: 1\nkind: workflow\nid: check-currency\nname: Check Currency\ndescription: Validate that a player has enough currency for a cost.\ndefinition:\n  params:\n    balance:\n      type: number\n    cost:\n      type: number\n  steps:\n    - id: has_currency\n      type: condition\n      check:\n        field: \"{{balance}}\"\n        op: \">=\"\n        value: \"{{cost}}\"\n      onFail:\n        status: 409\n        error: INSUFFICIENT_CURRENCY\n        message: Not enough currency.\n  returns:\n    ok: true\n"
      }
    ]
  }
}

Expected response status 200.

POST/v3/manage/{projectId}/test-endpoint

Contract tests
Not covered by the HTTP contract tests yet.

PUT/v3/manage/{projectId}/tests

Status codes in tests
200
Library call
Editor/SyncToolApi.cs (Request: x-api-key secret + x-public-key) AutoTest/RunTest/GetTests/UpgradeSource/GetSyncJobStatus
Example from the contract tests (manage-tests-and-tools / put-tests)
{
  "method": "PUT",
  "path": "/v3/manage/${projectId}/tests",
  "headers": {
    "x-api-key": "${secretKey}",
    "x-public-key": "${publicKey}",
    "Content-Type": "application/json"
  },
  "body": [
    {
      "id": "mine-ore-success",
      "endpoint": "mine-ore",
      "input": {
        "amount": 3
      },
      "expect": {
        "status": 200
      }
    }
  ]
}

Expected response status 200.

PATCH/v3/manage/{projectId}/workflows

Status codes in tests
200
Library call
Editor/sync.py (api_request: x-api-key secret + x-public-key, JSON body), Editor/SyncToolApi.cs PatchEndpoint/PatchCollection/PatchWorkflow
Example from the contract tests (manage-resource-crud / patch-workflow)
{
  "method": "PATCH",
  "path": "/v3/manage/${projectId}/workflows",
  "headers": {
    "x-api-key": "${secretKey}",
    "x-public-key": "${publicKey}",
    "Content-Type": "application/json"
  },
  "body": {
    "id": "is-positive",
    "name": "Is Positive",
    "builtIn": false,
    "description": "Reject when a computed value is zero or negative.",
    "condition": {
      "field": "{{value}}",
      "op": ">",
      "value": 0
    },
    "onFail": {
      "errorCode": "NO_VALUE",
      "errorMessage": "Value must be positive.",
      "status": 400
    },
    "params": {},
    "requires": {
      "value": {
        "description": "Value to validate."
      }
    },
    "returns": {},
    "steps": []
  }
}

Expected response status 200.

POST/v3/manage/{projectId}/workflows

Contract tests
Not covered by the HTTP contract tests yet.

PUT/v3/manage/{projectId}/workflows

Status codes in tests
200
Library call
Editor/sync.py (api_request: x-api-key secret + x-public-key, JSON body), Editor/SyncToolApi.cs PatchEndpoint/PatchCollection/PatchWorkflow
Example from the contract tests (manage-resource-crud / put-workflows)
{
  "method": "PUT",
  "path": "/v3/manage/${projectId}/workflows",
  "headers": {
    "x-api-key": "${secretKey}",
    "x-public-key": "${publicKey}",
    "Content-Type": "application/json"
  },
  "body": [
    {
      "id": "is-positive",
      "name": "Is Positive",
      "builtIn": false,
      "description": "Reject when a computed value is zero or negative.",
      "condition": {
        "field": "{{value}}",
        "op": ">",
        "value": 0
      },
      "onFail": {
        "errorCode": "NO_VALUE",
        "errorMessage": "Value must be positive.",
        "status": 400
      },
      "params": {},
      "requires": {
        "value": {
          "description": "Value to validate."
        }
      },
      "returns": {},
      "steps": []
    }
  ]
}

Expected response status 200.

DELETE/v3/manage/{projectId}/workflows/{workflowId}

Status codes in tests
200
Library call
Editor/sync.py (api_request: x-api-key secret + x-public-key, JSON body), Editor/SyncToolApi.cs PatchEndpoint/PatchCollection/PatchWorkflow
Example from the contract tests (manage-resource-crud / delete-workflow)
{
  "method": "DELETE",
  "path": "/v3/manage/${projectId}/workflows/is-positive",
  "headers": {
    "x-api-key": "${secretKey}",
    "x-public-key": "${publicKey}"
  }
}

Expected response status 200.

Queries /v3/queries

GET/v3/queries/{projectId}/{queryId}

Status codes in tests
200 401 404
Library call
Code/Storage/NetworkStorageQueries.cs GetQuery
Editor/SyncToolApi.cs, Code/Core/NetworkStorageHttp.cs
docs 09-error-codes
Example from the contract tests (queries-run / leaderboard)
{
  "method": "GET",
  "path": "/v3/queries/${projectId}/top_miners",
  "query": {
    "apiKey": "${publicKey}"
  },
  "headers": {
    "x-public-key": "${publicKey}"
  }
}

Expected response status 200.

Security config /v3/security-config

GET/v3/security-config/{projectId}

Status codes in tests
200 404
Example from the contract tests (runtime-security-config / security-config)
{
  "method": "GET",
  "path": "/v3/security-config/${projectId}"
}

Expected response status 200.

Server info /v3/server-info

GET/v3/server-info

Contract tests
Not covered by the HTTP contract tests yet.

Auth sessions (alias) /v3/sessions

POST/v3/sessions/{projectId}/create

Contract tests
Not covered by the HTTP contract tests yet.

POST/v3/sessions/{projectId}/reauth

Contract tests
Not covered by the HTTP contract tests yet.

POST/v3/sessions/{projectId}/refresh

Status codes in tests
200
Example from the contract tests (auth-sessions / sessions-alias)
{
  "method": "POST",
  "path": "/v3/sessions/${projectId}/refresh",
  "query": {
    "apiKey": "${publicKey}"
  },
  "headers": {
    "x-api-key": "${publicKey}"
  },
  "body": {}
}

Expected response status 200.

POST/v3/sessions/{projectId}/revoke

Contract tests
Not covered by the HTTP contract tests yet.

Documents, records and stats /v3/storage

GET/v3/storage

Status codes in tests
404
Example from the contract tests (errors-invalid-input / storage-root)
{
  "method": "GET",
  "path": "/v3/storage"
}

Expected response status 404.

DELETE/v3/storage/{projectId}/{collectionId}/{key}

Status codes in tests
200
Example from the contract tests (documents-player-crud / delete)
{
  "method": "DELETE",
  "path": "/v3/storage/${projectId}/players/${steamId}",
  "query": {
    "apiKey": "${publicKey}"
  },
  "headers": {
    "x-public-key": "${publicKey}",
    "x-steam-id": "${steamId}",
    "x-sbox-token": "parity-placeholder-token",
    "x-ns-client-type": "game"
  }
}

Expected response status 200.

GET/v3/storage/{projectId}/{collectionId}/{key}

Status codes in tests
200 401 404
Example from the contract tests (documents-player-crud / get-existing)
{
  "method": "GET",
  "path": "/v3/storage/${projectId}/players/${steamId}",
  "query": {
    "apiKey": "${publicKey}"
  },
  "headers": {
    "x-public-key": "${publicKey}",
    "x-steam-id": "${steamId}",
    "x-sbox-token": "parity-placeholder-token",
    "x-ns-client-type": "game"
  }
}

Expected response status 200.

POST/v3/storage/{projectId}/{collectionId}/{key}

Status codes in tests
200 400 413
Example from the contract tests (endpoints-player-flow / seed-economy)
{
  "method": "POST",
  "path": "/v3/storage/${projectId}/players/${steamId}",
  "query": {
    "apiKey": "${publicKey}"
  },
  "headers": {
    "x-public-key": "${publicKey}",
    "x-steam-id": "${steamId}",
    "x-sbox-token": "parity-placeholder-token",
    "x-ns-client-type": "game",
    "Content-Type": "application/json"
  },
  "body": {
    "playerName": "Parity Tester",
    "gold": 100,
    "level": 0,
    "ores": {
      "stone": 0
    }
  }
}

Expected response status 200.

GET/v3/storage/{projectId}/{collectionId}/{key}/probe

Status codes in tests
200
Example from the contract tests (documents-player-crud / probe)
{
  "method": "GET",
  "path": "/v3/storage/${projectId}/players/${steamId}/probe",
  "query": {
    "apiKey": "${publicKey}"
  },
  "headers": {
    "x-public-key": "${publicKey}",
    "x-steam-id": "${steamId}",
    "x-sbox-token": "parity-placeholder-token",
    "x-ns-client-type": "game"
  }
}

Expected response status 200.

GET/v3/storage/{projectId}/{collectionId}/{steamId}/ledger

Status codes in tests
200
Library call
docs 18-rest-api-reference (Ledger)
Example from the contract tests (ledger-read / ledger)
{
  "method": "GET",
  "path": "/v3/storage/${projectId}/players/${steamId}/ledger",
  "query": {
    "apiKey": "${publicKey}"
  },
  "headers": {
    "x-public-key": "${publicKey}",
    "x-steam-id": "${steamId}",
    "x-sbox-token": "parity-placeholder-token",
    "x-ns-client-type": "game"
  }
}

Expected response status 200.

GET/v3/storage/{projectId}/{collectionId}/{steamId}/records

Status codes in tests
200
Example from the contract tests (records-save-slots / list-empty)
{
  "method": "GET",
  "path": "/v3/storage/${projectId}/save_slots/${steamId}/records",
  "query": {
    "apiKey": "${publicKey}"
  },
  "headers": {
    "x-public-key": "${publicKey}",
    "x-steam-id": "${steamId}",
    "x-sbox-token": "parity-placeholder-token",
    "x-ns-client-type": "game",
    "x-api-key": "${secretKey}"
  }
}

Expected response status 200.

POST/v3/storage/{projectId}/{collectionId}/{steamId}/records

Status codes in tests
200
Example from the contract tests (records-save-slots / create-named)
{
  "method": "POST",
  "path": "/v3/storage/${projectId}/save_slots/${steamId}/records",
  "query": {
    "apiKey": "${publicKey}"
  },
  "headers": {
    "x-public-key": "${publicKey}",
    "x-steam-id": "${steamId}",
    "x-sbox-token": "parity-placeholder-token",
    "x-ns-client-type": "game",
    "x-api-key": "${secretKey}"
  },
  "body": {
    "recordName": "Main Save"
  }
}

Expected response status 200.

DELETE/v3/storage/{projectId}/{collectionId}/{steamId}/records/{recordId}

Status codes in tests
200 404
Example from the contract tests (records-save-slots / delete)
{
  "method": "DELETE",
  "path": "/v3/storage/${projectId}/save_slots/${steamId}/records/${capture.slotB}",
  "query": {
    "apiKey": "${publicKey}"
  },
  "headers": {
    "x-public-key": "${publicKey}",
    "x-steam-id": "${steamId}",
    "x-sbox-token": "parity-placeholder-token",
    "x-ns-client-type": "game",
    "x-api-key": "${secretKey}"
  }
}

Expected response status 200.

PATCH/v3/storage/{projectId}/{collectionId}/{steamId}/records/{recordId}

Status codes in tests
200 404
Example from the contract tests (records-save-slots / rename)
{
  "method": "PATCH",
  "path": "/v3/storage/${projectId}/save_slots/${steamId}/records/${capture.slotA}",
  "query": {
    "apiKey": "${publicKey}"
  },
  "headers": {
    "x-public-key": "${publicKey}",
    "x-steam-id": "${steamId}",
    "x-sbox-token": "parity-placeholder-token",
    "x-ns-client-type": "game",
    "x-api-key": "${secretKey}"
  },
  "body": {
    "recordName": "Renamed Save"
  }
}

Expected response status 200.

POST/v3/storage/{projectId}/{collectionId}/append

Status codes in tests
200 400 403 413
Library call
docs 18-rest-api-reference (Global Collections), 02a-collections-http-api
docs 13-quotas-and-usage
Example from the contract tests (global-append-list / append-first)
{
  "method": "POST",
  "path": "/v3/storage/${projectId}/leaderboard_global/append",
  "query": {
    "apiKey": "${publicKey}"
  },
  "headers": {
    "x-public-key": "${publicKey}",
    "x-api-key": "${secretKey}",
    "x-steam-id": "${steamId}",
    "Idempotency-Key": "parity-run-1"
  },
  "body": {
    "score": 1200,
    "playerName": "Parity Tester"
  }
}

Expected response status 200.

GET/v3/storage/{projectId}/{collectionId}/list

Status codes in tests
200
Library call
docs 18-rest-api-reference (Global Collections), 02a-collections-http-api
Example from the contract tests (global-append-list / list)
{
  "method": "GET",
  "path": "/v3/storage/${projectId}/leaderboard_global/list",
  "query": {
    "apiKey": "${publicKey}"
  },
  "headers": {
    "x-public-key": "${publicKey}"
  }
}

Expected response status 200.

GET/v3/storage/{projectId}/{collectionId}/record/{recordId}

Status codes in tests
200 404
Library call
docs 18-rest-api-reference (Global Collections), 02a-collections-http-api
Example from the contract tests (global-append-list / record)
{
  "method": "GET",
  "path": "/v3/storage/${projectId}/leaderboard_global/record/${capture.firstRecord}",
  "query": {
    "apiKey": "${publicKey}"
  },
  "headers": {
    "x-public-key": "${publicKey}"
  }
}

Expected response status 200.

POST/v3/storage/{projectId}/analytics/events

Status codes in tests
200 400
Example from the contract tests (analytics-and-heartbeat / analytics-event)
{
  "method": "POST",
  "path": "/v3/storage/${projectId}/analytics/events",
  "query": {
    "apiKey": "${publicKey}"
  },
  "headers": {
    "x-public-key": "${publicKey}",
    "x-steam-id": "${steamId}",
    "x-sbox-token": "parity-placeholder-token",
    "x-ns-client-type": "game"
  },
  "body": {
    "steamId": "${steamId}",
    "type": "level_complete",
    "severity": null,
    "label": "level_complete",
    "message": null,
    "stack": null,
    "context": {
      "level": 3,
      "durationSeconds": 42
    },
    "playerName": "Parity Tester",
    "sessionId": "parity-session-1",
    "source": "network-storage-library",
    "libraryVersion": "1.0.0",
    "packageIdent": "parity.testgame"
  }
}

Expected response status 200.

GET/v3/storage/{projectId}/rate-limits

Status codes in tests
200
Library call
docs 18-rest-api-reference (GET /v3/storage/{projectId}/rate-limits)
Example from the contract tests (runtime-rate-limits / rate-limits)
{
  "method": "GET",
  "path": "/v3/storage/${projectId}/rate-limits",
  "query": {
    "apiKey": "${publicKey}"
  },
  "headers": {
    "x-public-key": "${publicKey}"
  }
}

Expected response status 200.

GET/v3/storage/{projectId}/stats/{steamId}

Status codes in tests
200
Example from the contract tests (analytics-and-heartbeat / stats-read)
{
  "method": "GET",
  "path": "/v3/storage/${projectId}/stats/${steamId}",
  "query": {
    "apiKey": "${publicKey}"
  },
  "headers": {
    "x-public-key": "${publicKey}"
  }
}

Expected response status 200.

POST/v3/storage/{projectId}/stats/heartbeat

Status codes in tests
200
Example from the contract tests (analytics-and-heartbeat / heartbeat)
{
  "method": "POST",
  "path": "/v3/storage/${projectId}/stats/heartbeat",
  "query": {
    "apiKey": "${publicKey}"
  },
  "headers": {
    "x-public-key": "${publicKey}",
    "x-steam-id": "${steamId}",
    "x-sbox-token": "parity-placeholder-token",
    "x-ns-client-type": "game"
  },
  "body": {
    "steamId": "${steamId}",
    "sessionId": "parity-session-1",
    "sessionSeconds": 120,
    "event": "heartbeat",
    "playerName": "Parity Tester",
    "source": "network-storage-library",
    "libraryVersion": "1.0.0",
    "packageIdent": "parity.testgame",
    "context": {
      "map": "quarry"
    },
    "fps": {
      "avg": 60
    }
  }
}

Expected response status 200.

DELETE/v3/storage/deploy-canary/{**path}

Contract tests
Not covered by the HTTP contract tests yet.

GET/v3/storage/deploy-canary/{**path}

Status codes in tests
200
Example from the contract tests (errors-invalid-input / deploy-canary)
{
  "method": "GET",
  "path": "/v3/storage/deploy-canary/ping"
}

Expected response status 200.

HEAD/v3/storage/deploy-canary/{**path}

Contract tests
Not covered by the HTTP contract tests yet.

OPTIONS/v3/storage/deploy-canary/{**path}

Contract tests
Not covered by the HTTP contract tests yet.

PATCH/v3/storage/deploy-canary/{**path}

Contract tests
Not covered by the HTTP contract tests yet.

POST/v3/storage/deploy-canary/{**path}

Contract tests
Not covered by the HTTP contract tests yet.

PUT/v3/storage/deploy-canary/{**path}

Contract tests
Not covered by the HTTP contract tests yet.

Game values /v3/values

GET/v3/values/{projectId}

Status codes in tests
200 401
Example from the contract tests (runtime-values / values)
{
  "method": "GET",
  "path": "/v3/values/${projectId}",
  "query": {
    "apiKey": "${publicKey}"
  },
  "headers": {
    "x-public-key": "${publicKey}"
  }
}

Expected response status 200.

Health /health

GET/health

Contract tests
Not covered by the HTTP contract tests yet.

/pages /pages

GET/pages/{projectId}/{pageSlug}

Status codes in tests
404
Library call
docs 18-rest-api-reference (Pages API)
Example from the contract tests (runtime-pages / page-missing-short)
{
  "method": "GET",
  "path": "/pages/${projectId}/news"
}

Expected response status 404.

/api/network-storage /api/network-storage

POST/api/network-storage/{projectId}/save-failure

Contract tests
Not covered by the HTTP contract tests yet.

/api/pages /api/pages

GET/api/pages/{projectId}/{pageSlug}

Status codes in tests
404
Library call
docs 18-rest-api-reference (Pages API)
Example from the contract tests (runtime-pages / page-missing)
{
  "method": "GET",
  "path": "/api/pages/${projectId}/news",
  "query": {
    "apiKey": "${publicKey}"
  }
}

Expected response status 404.

Legacy storage alias /api/storage

GET/api/storage

Contract tests
Not covered by the HTTP contract tests yet.

DELETE/api/storage/{projectId}/{collectionId}/{key}

Status codes in tests
200
Library call
docs 18-rest-api-reference (Deprecated Routes)
Example from the contract tests (documents-v0-alias / delete)
{
  "method": "DELETE",
  "path": "/api/storage/${projectId}/players/v0-key",
  "query": {
    "apiKey": "${publicKey}"
  }
}

Expected response status 200.

GET/api/storage/{projectId}/{collectionId}/{key}

Status codes in tests
200 404
Library call
docs 18-rest-api-reference (Deprecated Routes)
docs 18-rest-api-reference (Global Collections), 02a-collections-http-api
Example from the contract tests (documents-v0-alias / get)
{
  "method": "GET",
  "path": "/api/storage/${projectId}/players/v0-key",
  "query": {
    "apiKey": "${publicKey}"
  }
}

Expected response status 200.

POST/api/storage/{projectId}/{collectionId}/{key}

Status codes in tests
200
Library call
docs 18-rest-api-reference (Deprecated Routes)
Example from the contract tests (documents-v0-alias / save)
{
  "method": "POST",
  "path": "/api/storage/${projectId}/players/v0-key",
  "query": {
    "apiKey": "${publicKey}"
  },
  "body": {
    "playerName": "Legacy"
  }
}

Expected response status 200.

GET/api/storage/{projectId}/{collectionId}/{steamId}/records

Contract tests
Not covered by the HTTP contract tests yet.

POST/api/storage/{projectId}/{collectionId}/{steamId}/records

Contract tests
Not covered by the HTTP contract tests yet.

DELETE/api/storage/{projectId}/{collectionId}/{steamId}/records/{recordId}

Contract tests
Not covered by the HTTP contract tests yet.

PATCH/api/storage/{projectId}/{collectionId}/{steamId}/records/{recordId}

Contract tests
Not covered by the HTTP contract tests yet.

POST/api/storage/{projectId}/{collectionId}/append

Contract tests
Not covered by the HTTP contract tests yet.

POST/api/storage/{projectId}/analytics/events

Contract tests
Not covered by the HTTP contract tests yet.

GET/api/storage/{projectId}/queries/{queryId}

Status codes in tests
200
Example from the contract tests (queries-run / api-storage-alias)
{
  "method": "GET",
  "path": "/api/storage/${projectId}/queries/top_miners",
  "query": {
    "apiKey": "${publicKey}"
  }
}

Expected response status 200.

POST/api/storage/{projectId}/stats/heartbeat

Status codes in tests
200
Example from the contract tests (analytics-and-heartbeat / heartbeat-api-alias)
{
  "method": "POST",
  "path": "/api/storage/${projectId}/stats/heartbeat",
  "query": {
    "apiKey": "${publicKey}"
  },
  "headers": {
    "x-public-key": "${publicKey}",
    "x-steam-id": "${steamId}",
    "x-sbox-token": "parity-placeholder-token",
    "x-ns-client-type": "game"
  },
  "body": {
    "steamId": "${steamId}",
    "sessionId": "parity-session-1",
    "sessionSeconds": 120,
    "event": "heartbeat",
    "playerName": "Parity Tester",
    "source": "network-storage-library",
    "libraryVersion": "1.0.0",
    "packageIdent": "parity.testgame",
    "context": {
      "map": "quarry"
    },
    "fps": {
      "avg": 60
    }
  }
}

Expected response status 200.

/v1/auth-sessions /v1/auth-sessions

POST/v1/auth-sessions/{projectId}/create

Contract tests
Not covered by the HTTP contract tests yet.

POST/v1/auth-sessions/{projectId}/reauth

Contract tests
Not covered by the HTTP contract tests yet.

POST/v1/auth-sessions/{projectId}/refresh

Contract tests
Not covered by the HTTP contract tests yet.

POST/v1/auth-sessions/{projectId}/revoke

Contract tests
Not covered by the HTTP contract tests yet.

Legacy v1 endpoints /v1/endpoints

POST/v1/endpoints/{projectId}

Contract tests
Not covered by the HTTP contract tests yet.

GET/v1/endpoints/{projectId}/{endpointSlug}

Contract tests
Not covered by the HTTP contract tests yet.

POST/v1/endpoints/{projectId}/{endpointSlug}

Status codes in tests
200
Example from the contract tests (endpoints-get-and-routing / post-v1-alias)
{
  "method": "POST",
  "path": "/v1/endpoints/${projectId}/load-profile",
  "query": {
    "apiKey": "${publicKey}"
  },
  "headers": {
    "x-public-key": "${publicKey}",
    "x-steam-id": "${steamId}",
    "x-sbox-token": "parity-placeholder-token",
    "x-ns-client-type": "game"
  },
  "body": {
    "security": {
      "configVersion": "",
      "clientMode": "legacy",
      "authSessions": "disabled",
      "encryptedRequests": "disabled",
      "revisionId": 0,
      "revisionOutdated": false
    },
    "_endpointSlug": "load-profile"
  }
}

Expected response status 200.

Legacy v1 queries /v1/queries

GET/v1/queries/{projectId}/{queryId}

Status codes in tests
200
Example from the contract tests (queries-run / leaderboard-v1)
{
  "method": "GET",
  "path": "/v1/queries/${projectId}/top_miners",
  "query": {
    "apiKey": "${publicKey}"
  },
  "headers": {
    "x-public-key": "${publicKey}"
  }
}

Expected response status 200.

/v1/sessions /v1/sessions

POST/v1/sessions/{projectId}/create

Contract tests
Not covered by the HTTP contract tests yet.

POST/v1/sessions/{projectId}/reauth

Contract tests
Not covered by the HTTP contract tests yet.

POST/v1/sessions/{projectId}/refresh

Contract tests
Not covered by the HTTP contract tests yet.

POST/v1/sessions/{projectId}/revoke

Contract tests
Not covered by the HTTP contract tests yet.

Legacy v1 storage /v1/storage

GET/v1/storage/{projectId}/{collectionId}/{steamId}/records

Contract tests
Not covered by the HTTP contract tests yet.

POST/v1/storage/{projectId}/{collectionId}/{steamId}/records

Contract tests
Not covered by the HTTP contract tests yet.

DELETE/v1/storage/{projectId}/{collectionId}/{steamId}/records/{recordId}

Contract tests
Not covered by the HTTP contract tests yet.

PATCH/v1/storage/{projectId}/{collectionId}/{steamId}/records/{recordId}

Contract tests
Not covered by the HTTP contract tests yet.

GET/v1/storage/{projectId}/rate-limits

Status codes in tests
200
Library call
docs 18-rest-api-reference (GET /v3/storage/{projectId}/rate-limits)
Example from the contract tests (runtime-rate-limits / rate-limits-v1)
{
  "method": "GET",
  "path": "/v1/storage/${projectId}/rate-limits",
  "query": {
    "apiKey": "${publicKey}"
  },
  "headers": {
    "x-public-key": "${publicKey}"
  }
}

Expected response status 200.

Legacy v1 game values /v1/values

GET/v1/values/{projectId}

Status codes in tests
200
Example from the contract tests (runtime-values / values-v1-alias)
{
  "method": "GET",
  "path": "/v1/values/${projectId}",
  "query": {
    "apiKey": "${publicKey}"
  },
  "headers": {
    "x-public-key": "${publicKey}"
  }
}

Expected response status 200.

Generated from sbox-cool/sbox-network-storage-server Endpoints + tests/parity/corpus at v0.5.4 (d35738b).