{"activeVersionTag":"latest","latestAvailableVersionTag":"latest","collection":{"info":{"_postman_id":"9e4ae121-2cf2-4f11-bf5c-8fefb1b77b22","name":"B3 Docs","description":"Welcome to the Basement.fun documentation! This guide will help you integrate your game with our platform using B3’s API. By following these steps, you’ll discover how to effortlessly connect your game and unlock a range of exciting features and functionalities.\n\nSee more documentation at [https://docs.b3.fun](https://docs.b3.fun)\n\n## **Authorization**\n\nTo call the APIs, there are two steps of authorization. The launcherJwt (A JSON-Web-Token that links to the specific user's session with the game (passed in the request body), and the client secret (passed as Authorization header)\n\n##### Obtaining a Launcher JWT For:\n\n1. Embedded games in launcher, or external web games: the launcher loads the link of the game with an additional query parameter which contains the token. Easy.  \n    i.e if the game's target is `example.com` the launcher will load `example.com/?token=`.\n    \n2. External non-web games (Telegram, desktop, etc.): to get a JWT and maintain the session, you must manually create a session and call the heartbeat API to keep it alive.\n    \n    1. Call CreateUnverifiedChannel to create a new session for the user.\n        \n    2. Get the \"signRequest\" value from the response and have your user sign it with their wallet.\n        \n    3. Call VerifyUnverifiedChannel with the user's sign hash to verify their presence. Get the launcherJwt from its response and use for all other API calls.\n        \n    4. Keep the session alive by calling RenewChannelHeartbeat at least once every 3 minutes. Capture authentication errors from the APIs and repeat from a if the JWT has expired.\n        \n\n## Session Management (Important for external games)\n\nIn order for B3 to accurately measure user metrics of the game, and to provide the APIs via valid sessions that use JWT for authorization, we require the user context to continuously keep the session alive using the heartbeat APIs.\n\n- For embedded games: We manually maintain the session, no required integration on the game's side.\n    \n- For external WEB games: When your game is opened in a new window, we pass the session JWT as an additional query parameter. You can either use it to manually call the heartbeat API every 3 minutes, OR, simply use our already made script which does this all automatically for you.\n    \n    - Simply add the following HTML code to all the html pages of your game\n        \n        - ``` `https://cdn.basement.fun/heartbeat-script.js``\" type=\"text/javascript\">` ```\n            \n- `For external non-web games (i.e Telegram), follow the instructions of \"Obtaining a Launcher JWT For: [external non-web games]\"`\n    \n\n## Payload Verification - Anti client-side request forgery\n\nBy default, requests going to the backend from your client-side game, will appear in the devtools window of the browser. Devtools lets users easily edit and resend requests, which means that anyone with a basic technical knowledge could edit outgoing requests, and increase their scores, or otherwise modify their data.\n\nTo ensure that is not possible, we offer a feature flag for games, \"launcherSignatureVerification\" (can be turned on in dashboard), which adds an additional layer of authentication with each request.\n\n**How to sign requests using launcher signature verification:**\n\n1. Take your game's secret, hash it using MD5, and store it in the game.\n    \n2. For each request to the basement API, construct and include the following headers:\n    \n    1. \"X-Request-Nonce\": a random string, identifier for the specific request. (we recommend up to 32 randomly selected characters)\n        \n    2. \"X-Request-Signature\": this is the MD5 hash of the nonce prepended to the md5 of the game's secret ( = MD5(nonce + MD5(gameSecret))\n        \n\nWith this enabled, each request signature is unique, and validated to ensure the it is useable only once. Now if a user attempts to modify a request and resend it with the same signature, they will be flagged as potential cheater, and the request will fail.","schema":"https://schema.getpostman.com/json/collection/v2.0.0/collection.json","isPublicCollection":false,"owner":"37856942","team":6409111,"collectionId":"9e4ae121-2cf2-4f11-bf5c-8fefb1b77b22","publishedId":"2sAXjF7u4i","public":true,"publicUrl":"https://docs.basement.fun","privateUrl":"https://go.postman.co/documentation/37856942-9e4ae121-2cf2-4f11-bf5c-8fefb1b77b22","customColor":{"top-bar":"FFFFFF","right-sidebar":"303030","highlight":"8d4cf6"},"documentationLayout":"classic-double-column","customisation":{"metaTags":[{"name":"description","value":"Integrate your game into BSMNT, the onchain gaming discovery platform to natively play crypto games on B3."},{"name":"title","value":"Basement.fun API Docs"}],"appearance":{"default":"dark","themes":[{"name":"dark","logo":null,"colors":{"top-bar":"14121c","right-sidebar":"100e14","highlight":"8d4cf6"}},{"name":"light","logo":null,"colors":{"top-bar":"FFFFFF","right-sidebar":"303030","highlight":"8d4cf6"}}]}},"version":"8.10.0","publishDate":"2024-08-23T17:56:47.000Z","activeVersionTag":"latest","documentationTheme":"light","metaTags":{"title":"Basement.fun API Docs","description":"Integrate your game into BSMNT, the onchain gaming discovery platform to natively play crypto games on B3."},"logos":{"logoLight":null,"logoDark":null}},"statusCode":200},"environments":[],"user":{"authenticated":false,"permissions":{"publish":false}},"run":{"button":{"js":"https://run.pstmn.io/button.js","css":"https://run.pstmn.io/button.css"}},"web":"https://www.getpostman.com/","team":{"logo":"https://res.cloudinary.com/postman/image/upload/t_team_logo_pubdoc/v1/team/e8bb085a3defde02d7ebd75e54c8a6a509a393eac5b672a2ff8647219b4d5a86","favicon":"https://res.cloudinary.com/postman/image/upload/v1724434849/team/f591e9b6f389f3f193ff452c4aeba8b9.ico"},"isEnvFetchError":false,"languages":"[{\"key\":\"csharp\",\"label\":\"C#\",\"variant\":\"HttpClient\"},{\"key\":\"csharp\",\"label\":\"C#\",\"variant\":\"RestSharp\"},{\"key\":\"curl\",\"label\":\"cURL\",\"variant\":\"cURL\"},{\"key\":\"dart\",\"label\":\"Dart\",\"variant\":\"http\"},{\"key\":\"go\",\"label\":\"Go\",\"variant\":\"Native\"},{\"key\":\"http\",\"label\":\"HTTP\",\"variant\":\"HTTP\"},{\"key\":\"java\",\"label\":\"Java\",\"variant\":\"OkHttp\"},{\"key\":\"java\",\"label\":\"Java\",\"variant\":\"Unirest\"},{\"key\":\"javascript\",\"label\":\"JavaScript\",\"variant\":\"Fetch\"},{\"key\":\"javascript\",\"label\":\"JavaScript\",\"variant\":\"jQuery\"},{\"key\":\"javascript\",\"label\":\"JavaScript\",\"variant\":\"XHR\"},{\"key\":\"c\",\"label\":\"C\",\"variant\":\"libcurl\"},{\"key\":\"nodejs\",\"label\":\"NodeJs\",\"variant\":\"Axios\"},{\"key\":\"nodejs\",\"label\":\"NodeJs\",\"variant\":\"Native\"},{\"key\":\"nodejs\",\"label\":\"NodeJs\",\"variant\":\"Request\"},{\"key\":\"nodejs\",\"label\":\"NodeJs\",\"variant\":\"Unirest\"},{\"key\":\"objective-c\",\"label\":\"Objective-C\",\"variant\":\"NSURLSession\"},{\"key\":\"ocaml\",\"label\":\"OCaml\",\"variant\":\"Cohttp\"},{\"key\":\"php\",\"label\":\"PHP\",\"variant\":\"cURL\"},{\"key\":\"php\",\"label\":\"PHP\",\"variant\":\"Guzzle\"},{\"key\":\"php\",\"label\":\"PHP\",\"variant\":\"HTTP_Request2\"},{\"key\":\"php\",\"label\":\"PHP\",\"variant\":\"pecl_http\"},{\"key\":\"powershell\",\"label\":\"PowerShell\",\"variant\":\"RestMethod\"},{\"key\":\"python\",\"label\":\"Python\",\"variant\":\"http.client\"},{\"key\":\"python\",\"label\":\"Python\",\"variant\":\"Requests\"},{\"key\":\"r\",\"label\":\"R\",\"variant\":\"httr\"},{\"key\":\"r\",\"label\":\"R\",\"variant\":\"RCurl\"},{\"key\":\"ruby\",\"label\":\"Ruby\",\"variant\":\"Net::HTTP\"},{\"key\":\"shell\",\"label\":\"Shell\",\"variant\":\"Httpie\"},{\"key\":\"shell\",\"label\":\"Shell\",\"variant\":\"wget\"},{\"key\":\"swift\",\"label\":\"Swift\",\"variant\":\"URLSession\"}]","languageSettings":[{"key":"csharp","label":"C#","variant":"HttpClient"},{"key":"csharp","label":"C#","variant":"RestSharp"},{"key":"curl","label":"cURL","variant":"cURL"},{"key":"dart","label":"Dart","variant":"http"},{"key":"go","label":"Go","variant":"Native"},{"key":"http","label":"HTTP","variant":"HTTP"},{"key":"java","label":"Java","variant":"OkHttp"},{"key":"java","label":"Java","variant":"Unirest"},{"key":"javascript","label":"JavaScript","variant":"Fetch"},{"key":"javascript","label":"JavaScript","variant":"jQuery"},{"key":"javascript","label":"JavaScript","variant":"XHR"},{"key":"c","label":"C","variant":"libcurl"},{"key":"nodejs","label":"NodeJs","variant":"Axios"},{"key":"nodejs","label":"NodeJs","variant":"Native"},{"key":"nodejs","label":"NodeJs","variant":"Request"},{"key":"nodejs","label":"NodeJs","variant":"Unirest"},{"key":"objective-c","label":"Objective-C","variant":"NSURLSession"},{"key":"ocaml","label":"OCaml","variant":"Cohttp"},{"key":"php","label":"PHP","variant":"cURL"},{"key":"php","label":"PHP","variant":"Guzzle"},{"key":"php","label":"PHP","variant":"HTTP_Request2"},{"key":"php","label":"PHP","variant":"pecl_http"},{"key":"powershell","label":"PowerShell","variant":"RestMethod"},{"key":"python","label":"Python","variant":"http.client"},{"key":"python","label":"Python","variant":"Requests"},{"key":"r","label":"R","variant":"httr"},{"key":"r","label":"R","variant":"RCurl"},{"key":"ruby","label":"Ruby","variant":"Net::HTTP"},{"key":"shell","label":"Shell","variant":"Httpie"},{"key":"shell","label":"Shell","variant":"wget"},{"key":"swift","label":"Swift","variant":"URLSession"}],"languageOptions":[{"label":"C# - HttpClient","value":"csharp - HttpClient - C#"},{"label":"C# - RestSharp","value":"csharp - RestSharp - C#"},{"label":"cURL - cURL","value":"curl - cURL - cURL"},{"label":"Dart - http","value":"dart - http - Dart"},{"label":"Go - Native","value":"go - Native - Go"},{"label":"HTTP - HTTP","value":"http - HTTP - HTTP"},{"label":"Java - OkHttp","value":"java - OkHttp - Java"},{"label":"Java - Unirest","value":"java - Unirest - Java"},{"label":"JavaScript - Fetch","value":"javascript - Fetch - JavaScript"},{"label":"JavaScript - jQuery","value":"javascript - jQuery - JavaScript"},{"label":"JavaScript - XHR","value":"javascript - XHR - JavaScript"},{"label":"C - libcurl","value":"c - libcurl - C"},{"label":"NodeJs - Axios","value":"nodejs - Axios - NodeJs"},{"label":"NodeJs - Native","value":"nodejs - Native - NodeJs"},{"label":"NodeJs - Request","value":"nodejs - Request - NodeJs"},{"label":"NodeJs - Unirest","value":"nodejs - Unirest - NodeJs"},{"label":"Objective-C - NSURLSession","value":"objective-c - NSURLSession - Objective-C"},{"label":"OCaml - Cohttp","value":"ocaml - Cohttp - OCaml"},{"label":"PHP - cURL","value":"php - cURL - PHP"},{"label":"PHP - Guzzle","value":"php - Guzzle - PHP"},{"label":"PHP - HTTP_Request2","value":"php - HTTP_Request2 - PHP"},{"label":"PHP - pecl_http","value":"php - pecl_http - PHP"},{"label":"PowerShell - RestMethod","value":"powershell - RestMethod - PowerShell"},{"label":"Python - http.client","value":"python - http.client - Python"},{"label":"Python - Requests","value":"python - Requests - Python"},{"label":"R - httr","value":"r - httr - R"},{"label":"R - RCurl","value":"r - RCurl - R"},{"label":"Ruby - Net::HTTP","value":"ruby - Net::HTTP - Ruby"},{"label":"Shell - Httpie","value":"shell - Httpie - Shell"},{"label":"Shell - wget","value":"shell - wget - Shell"},{"label":"Swift - URLSession","value":"swift - URLSession - Swift"}],"layoutOptions":[{"value":"classic-single-column","label":"Single Column"},{"value":"classic-double-column","label":"Double Column"}],"versionOptions":[],"environmentOptions":[{"value":"0","label":"No Environment"}],"canonicalUrl":"https://docs.basement.fun/view/metadata/2sAXjF7u4i"}