horizon-mcp 1.5.0 → 1.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 ProjectMakers
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -28,7 +28,7 @@ Add to your MCP client configuration (Claude Desktop, Cursor, etc.):
28
28
 
29
29
  ## Features
30
30
 
31
- ### Resources (13 docs)
31
+ ### Resources (16 docs)
32
32
 
33
33
  Documentation resources are served directly from the MCP server. No API key required.
34
34
 
@@ -39,16 +39,19 @@ Documentation resources are served directly from the MCP server. No API key requ
39
39
  | `horizon://docs/leaderboard` | Leaderboard score submission, top entries, user rank, entries around user, with SDK examples |
40
40
  | `horizon://docs/cloud-save` | Cloud save/load for JSON and binary data, tier size limits, SDK examples |
41
41
  | `horizon://docs/remote-config` | Server-side key-value configuration: feature flags, game balance, A/B testing. SDK examples |
42
+ | `horizon://docs/localization` | Server-side localized strings across 15 languages: per-key translations, single/all fetch, available languages. SDK examples |
42
43
  | `horizon://docs/news` | In-game news and announcements with language filtering. SDK examples |
43
44
  | `horizon://docs/gift-codes` | Gift code validation and redemption for promotional rewards. SDK examples |
44
45
  | `horizon://docs/feedback` | Bug reports, feature requests, and general feedback submission. SDK examples |
45
46
  | `horizon://docs/user-logs` | Server-side event and error tracking. Requires BASIC tier or higher. SDK examples |
47
+ | `horizon://docs/crash-reporting` | Crash report submission, session tracking, fingerprinting, breadcrumbs, and auto-regression detection. SDK examples |
48
+ | `horizon://docs/email-sending` | Transactional and event-based email delivery to registered users. Templates, scheduling, status tracking, and SMTP integration. SDK examples |
46
49
  | `horizon://api/reference` | Complete API reference for all horizOn App API endpoints with request/response schemas |
47
50
  | `horizon://quickstart/godot` | Step-by-step guide to integrate horizOn in Godot with GDScript examples |
48
51
  | `horizon://quickstart/unity` | Step-by-step guide to integrate horizOn in Unity with C# examples |
49
- | `horizon://quickstart/unreal` | Guide to integrate horizOn in Unreal Engine using REST API. C++ and cURL examples |
52
+ | `horizon://quickstart/unreal` | Step-by-step guide to integrate horizOn in Unreal Engine 5.5+ with the official horizOn SDK plugin. C++ and Blueprint examples |
50
53
 
51
- ### Tools (19 tools)
54
+ ### Tools (28 tools)
52
55
 
53
56
  Live API tools that call the horizOn backend. Requires a valid API key.
54
57
 
@@ -69,11 +72,19 @@ Live API tools that call the horizOn backend. Requires a valid API key.
69
72
  | `horizon_load_cloud_data` | Load cloud save data for a user |
70
73
  | `horizon_get_remote_config` | Get a single remote config value by key |
71
74
  | `horizon_get_all_remote_configs` | Get all remote config values |
75
+ | `horizon_get_localization` | Get a single localized string by key, optionally for a specific language |
76
+ | `horizon_get_all_localizations` | Get all localized strings, optionally for a specific language |
77
+ | `horizon_get_localization_languages` | List the languages that have localizations for the app |
72
78
  | `horizon_get_news` | Get news articles with optional language filtering |
73
79
  | `horizon_validate_gift_code` | Validate a gift code without redeeming it |
74
80
  | `horizon_redeem_gift_code` | Redeem a gift code for a user |
75
81
  | `horizon_submit_feedback` | Submit user feedback (bug reports, feature requests) |
76
82
  | `horizon_create_log` | Create a server-side log entry (INFO, WARN, ERROR) |
83
+ | `horizon_create_crash_report` | Submit a crash report (grouped by fingerprint, with regression detection) |
84
+ | `horizon_create_crash_session` | Register a game session for the crash-free rate |
85
+ | `horizon_send_email` | Send a transactional email to a registered user from a template |
86
+ | `horizon_cancel_email` | Cancel a pending or scheduled email |
87
+ | `horizon_get_email_status` | Get the status of a sent or scheduled email |
77
88
 
78
89
  ### Prompts (4 prompts)
79
90
 
@@ -159,14 +170,17 @@ horizOn is a multi-tenant Backend-as-a-Service platform built for game and app d
159
170
 
160
171
  Core features:
161
172
 
162
- - Authentication (Anonymous, Email, Google)
173
+ - Authentication (Anonymous, Email, Google, Apple)
163
174
  - Leaderboards
164
175
  - Cloud Save
165
176
  - Remote Config
177
+ - Localization
166
178
  - News and Announcements
167
179
  - Gift Codes
168
180
  - User Feedback
169
181
  - User Logs
182
+ - Crash Reporting
183
+ - Email Sending
170
184
 
171
185
  Learn more at [horizon.pm](https://horizon.pm). Install this MCP server via [npm](https://www.npmjs.com/package/horizon-mcp).
172
186
 
@@ -174,13 +188,13 @@ Learn more at [horizon.pm](https://horizon.pm). Install this MCP server via [npm
174
188
 
175
189
  - **Godot 4.5+** -- GDScript SDK
176
190
  - **Unity 6** -- C# SDK
177
- - **Unreal Engine** -- REST API (no official SDK)
191
+ - **Unreal Engine 5.5+** -- C++ and Blueprint SDK
178
192
 
179
193
  ## Development
180
194
 
181
195
  ```bash
182
196
  # Clone the repository
183
- git clone https://github.com/nicokimmel/horizOn-mcp.git
197
+ git clone https://github.com/ProjectMakersDE/horizOn-mcp.git
184
198
  cd horizOn-mcp
185
199
 
186
200
  # Install dependencies
@@ -27,7 +27,7 @@ export function registerIntegrateFeaturePrompt(server) {
27
27
  role: "user",
28
28
  content: {
29
29
  type: "text",
30
- text: `I want to integrate the horizOn "${feature}" feature into my ${engine} project.\n\nPlease:\n1. Read the horizOn documentation for this feature (resource: horizon://docs/${feature})\n2. Read the ${engine} quickstart guide (resource: horizon://quickstart/${engine})\n3. Generate complete, production-ready integration code\n4. Include error handling and best practices\n5. Show how to test it works using the horizOn MCP tools\n\nUse the horizOn SDK for ${engine === "godot" ? "Godot (GDScript)" : engine === "unity" ? "Unity (C#)" : "Unreal Engine (REST/HTTP, no SDK)"}`,
30
+ text: `I want to integrate the horizOn "${feature}" feature into my ${engine} project.\n\nPlease:\n1. Read the horizOn documentation for this feature (resource: horizon://docs/${feature})\n2. Read the ${engine} quickstart guide (resource: horizon://quickstart/${engine})\n3. Generate complete, production-ready integration code\n4. Include error handling and best practices\n5. Show how to test it works using the horizOn MCP tools\n\nUse the horizOn SDK for ${engine === "godot" ? "Godot (GDScript)" : engine === "unity" ? "Unity (C#)" : "Unreal Engine (C++ and Blueprints)"}`,
31
31
  },
32
32
  },
33
33
  ],
@@ -1 +1 @@
1
- {"version":3,"file":"integrate-feature.js","sourceRoot":"","sources":["../../src/prompts/integrate-feature.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,QAAQ,CAAC;AAE3B,MAAM,UAAU,8BAA8B,CAAC,MAAiB;IAC9D,MAAM,CAAC,cAAc,CAAC,mBAAmB,EAAE;QACzC,KAAK,EAAE,2BAA2B;QAClC,WAAW,EACT,+EAA+E;QACjF,UAAU,EAAE;YACV,OAAO,EAAE,CAAC;iBACP,IAAI,CAAC;gBACJ,MAAM;gBACN,aAAa;gBACb,YAAY;gBACZ,eAAe;gBACf,MAAM;gBACN,YAAY;gBACZ,UAAU;gBACV,WAAW;gBACX,iBAAiB;aAClB,CAAC;iBACD,QAAQ,CAAC,kCAAkC,CAAC;YAC/C,MAAM,EAAE,CAAC;iBACN,IAAI,CAAC,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC;iBAClC,QAAQ,CAAC,iBAAiB,CAAC;SAC/B;KACF,EAAE,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,CAAC;QAC3B,QAAQ,EAAE;YACR;gBACE,IAAI,EAAE,MAAe;gBACrB,OAAO,EAAE;oBACP,IAAI,EAAE,MAAe;oBACrB,IAAI,EAAE,oCAAoC,OAAO,qBAAqB,MAAM,sGAAsG,OAAO,kBAAkB,MAAM,qDAAqD,MAAM,iMAAiM,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,mCAAmC,EAAE;iBACjkB;aACF;SACF;KACF,CAAC,CAAC,CAAC;AACN,CAAC"}
1
+ {"version":3,"file":"integrate-feature.js","sourceRoot":"","sources":["../../src/prompts/integrate-feature.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,QAAQ,CAAC;AAE3B,MAAM,UAAU,8BAA8B,CAAC,MAAiB;IAC9D,MAAM,CAAC,cAAc,CAAC,mBAAmB,EAAE;QACzC,KAAK,EAAE,2BAA2B;QAClC,WAAW,EACT,+EAA+E;QACjF,UAAU,EAAE;YACV,OAAO,EAAE,CAAC;iBACP,IAAI,CAAC;gBACJ,MAAM;gBACN,aAAa;gBACb,YAAY;gBACZ,eAAe;gBACf,MAAM;gBACN,YAAY;gBACZ,UAAU;gBACV,WAAW;gBACX,iBAAiB;aAClB,CAAC;iBACD,QAAQ,CAAC,kCAAkC,CAAC;YAC/C,MAAM,EAAE,CAAC;iBACN,IAAI,CAAC,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC;iBAClC,QAAQ,CAAC,iBAAiB,CAAC;SAC/B;KACF,EAAE,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,CAAC;QAC3B,QAAQ,EAAE;YACR;gBACE,IAAI,EAAE,MAAe;gBACrB,OAAO,EAAE;oBACP,IAAI,EAAE,MAAe;oBACrB,IAAI,EAAE,oCAAoC,OAAO,qBAAqB,MAAM,sGAAsG,OAAO,kBAAkB,MAAM,qDAAqD,MAAM,iMAAiM,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,oCAAoC,EAAE;iBAClkB;aACF;SACF;KACF,CAAC,CAAC,CAAC;AACN,CAAC"}
@@ -235,7 +235,7 @@ export function registerAllResources(server) {
235
235
  // Quickstart: Unreal
236
236
  server.registerResource("quickstart-unreal", "horizon://quickstart/unreal", {
237
237
  title: "Unreal Engine Quickstart",
238
- description: "Guide to integrate horizOn in Unreal Engine using REST API (no official SDK). C++ and cURL examples.",
238
+ description: "Step-by-step guide to integrate horizOn in Unreal Engine 5.5+ with the official horizOn SDK plugin. C++ and Blueprint examples.",
239
239
  mimeType: "text/markdown",
240
240
  }, () => ({
241
241
  contents: [
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/resources/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/resources/index.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAKpE,wBAAgB,YAAY,IAAI,SAAS,CAWxC"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAMpE,wBAAgB,YAAY,IAAI,SAAS,CAWxC"}
package/dist/server.js CHANGED
@@ -1,11 +1,12 @@
1
1
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { readFileSync } from "node:fs";
2
3
  import { registerAllResources } from "./resources/index.js";
3
4
  import { registerAllTools } from "./tools/index.js";
4
5
  import { registerAllPrompts } from "./prompts/index.js";
5
6
  export function createServer() {
6
7
  const server = new McpServer({
7
8
  name: "horizon-mcp",
8
- version: "0.1.0",
9
+ version: JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf8")).version,
9
10
  });
10
11
  registerAllResources(server);
11
12
  registerAllTools(server);
@@ -1 +1 @@
1
- {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAExD,MAAM,UAAU,YAAY;IAC1B,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;QAC3B,IAAI,EAAE,aAAa;QACnB,OAAO,EAAE,OAAO;KACjB,CAAC,CAAC;IAEH,oBAAoB,CAAC,MAAM,CAAC,CAAC;IAC7B,gBAAgB,CAAC,MAAM,CAAC,CAAC;IACzB,kBAAkB,CAAC,MAAM,CAAC,CAAC;IAE3B,OAAO,MAAM,CAAC;AAChB,CAAC"}
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAExD,MAAM,UAAU,YAAY;IAC1B,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;QAC3B,IAAI,EAAE,aAAa;QACnB,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,GAAG,CAAC,iBAAiB,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,OAAO;KAC/F,CAAC,CAAC;IAEH,oBAAoB,CAAC,MAAM,CAAC,CAAC;IAC7B,gBAAgB,CAAC,MAAM,CAAC,CAAC;IACzB,kBAAkB,CAAC,MAAM,CAAC,CAAC;IAE3B,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=admin-news.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"admin-news.test.d.ts","sourceRoot":"","sources":["../../../src/tools/__tests__/admin-news.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,64 @@
1
+ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
2
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
+ import { Client } from "@modelcontextprotocol/sdk/client/index.js";
4
+ import { InMemoryTransport } from "@modelcontextprotocol/sdk/inMemory.js";
5
+ import { registerAdminNewsTools } from "../admin/news.js";
6
+ // Contract checked against horizOn-Server NewsService.applyPublicationState and
7
+ // CreateNewsRequest/UpdateNewsRequest on 2026-09-23. Never call a live API here.
8
+ describe("admin news scheduling over MCP", () => {
9
+ let server;
10
+ let client;
11
+ let request;
12
+ const id = "11111111-1111-4111-8111-111111111111";
13
+ const input = {
14
+ projectApiKeyId: id, titles: { de: "Neu", en: "New" },
15
+ messages: { de: "Nachricht", en: "Message" },
16
+ releaseDate: "2026-09-24T12:30:00",
17
+ };
18
+ beforeEach(async () => {
19
+ vi.stubEnv("HORIZON_ACCOUNT_API_KEY", "test-account-key");
20
+ vi.stubEnv("HORIZON_BASE_URL", "https://news.test.invalid");
21
+ request = vi.fn().mockResolvedValue(new Response(JSON.stringify({ id })));
22
+ vi.stubGlobal("fetch", request);
23
+ server = new McpServer({ name: "test", version: "1.0.0" });
24
+ registerAdminNewsTools(server);
25
+ client = new Client({ name: "test", version: "1.0.0" });
26
+ const [a, b] = InMemoryTransport.createLinkedPair();
27
+ await Promise.all([server.connect(a), client.connect(b)]);
28
+ });
29
+ afterEach(async () => {
30
+ await client.close();
31
+ await server.close();
32
+ vi.unstubAllEnvs();
33
+ vi.unstubAllGlobals();
34
+ });
35
+ it("advertises scheduling for create and update", async () => {
36
+ const { tools } = await client.listTools();
37
+ for (const action of ["create", "update"]) {
38
+ expect(tools.find(t => t.name === `horizon_admin_news_${action}`)?.inputSchema.properties)
39
+ .toHaveProperty("isScheduled");
40
+ }
41
+ });
42
+ it.each([true, false])("forwards isScheduled=%s on create", async (isScheduled) => {
43
+ const result = await client.callTool({ name: "horizon_admin_news_create", arguments: { ...input, isPublished: false, isScheduled } });
44
+ expect(result.isError).not.toBe(true);
45
+ const [url, options] = request.mock.calls[0];
46
+ expect(url).toBe("https://news.test.invalid/api/v1/admin/news");
47
+ expect(options.headers["X-Account-API-Key"]).toBe("test-account-key");
48
+ expect(JSON.parse(options.body)).toEqual({ apiKeyId: id, titles: input.titles, messages: input.messages, releaseDate: input.releaseDate, isPublished: false, isScheduled });
49
+ });
50
+ it.each([true, false])("forwards isScheduled=%s on update", async (isScheduled) => {
51
+ await client.callTool({ name: "horizon_admin_news_update", arguments: { id, isScheduled, releaseDate: input.releaseDate } });
52
+ expect(JSON.parse(request.mock.calls[0][1].body)).toEqual({ isScheduled, releaseDate: input.releaseDate });
53
+ });
54
+ it("keeps omitted scheduling absent on partial update", async () => {
55
+ await client.callTool({ name: "horizon_admin_news_update", arguments: { id, titles: input.titles } });
56
+ expect(JSON.parse(request.mock.calls[0][1].body)).toEqual({ titles: input.titles });
57
+ });
58
+ it.each(["create", "update"])("rejects published plus scheduled for %s before HTTP", async (action) => {
59
+ const result = await client.callTool({ name: `horizon_admin_news_${action}`, arguments: { ...(action === "create" ? input : { id }), isPublished: true, isScheduled: true } });
60
+ expect(result.isError).toBe(true);
61
+ expect(request).not.toHaveBeenCalled();
62
+ });
63
+ });
64
+ //# sourceMappingURL=admin-news.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"admin-news.test.js","sourceRoot":"","sources":["../../../src/tools/__tests__/admin-news.test.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"news.d.ts","sourceRoot":"","sources":["../../../src/tools/admin/news.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAepE,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA8P9D"}
1
+ {"version":3,"file":"news.d.ts","sourceRoot":"","sources":["../../../src/tools/admin/news.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAepE,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA4Q9D"}
@@ -105,12 +105,19 @@ export function registerAdminNewsTools(server) {
105
105
  .boolean()
106
106
  .optional()
107
107
  .describe("Whether to publish on creation (default false)"),
108
+ isScheduled: z
109
+ .boolean()
110
+ .optional()
111
+ .describe("Publish automatically when releaseDate is due (default false). Cannot be true with isPublished."),
108
112
  },
109
- }, async ({ projectApiKeyId, titles, messages, releaseDate, isPublished, }) => {
113
+ }, async ({ projectApiKeyId, titles, messages, releaseDate, isPublished, isScheduled, }) => {
110
114
  const client = getAdminClient();
111
115
  if (!client)
112
116
  return noAdminClientResponse();
113
117
  try {
118
+ if (isPublished && isScheduled) {
119
+ return errorResponse(new Error("isPublished and isScheduled cannot both be true"));
120
+ }
114
121
  const body = {
115
122
  apiKeyId: projectApiKeyId,
116
123
  titles,
@@ -119,6 +126,8 @@ export function registerAdminNewsTools(server) {
119
126
  };
120
127
  if (isPublished !== undefined)
121
128
  body.isPublished = isPublished;
129
+ if (isScheduled !== undefined)
130
+ body.isScheduled = isScheduled;
122
131
  const result = await client.post("/api/v1/admin/news", body);
123
132
  return jsonResponse(result);
124
133
  }
@@ -139,13 +148,17 @@ export function registerAdminNewsTools(server) {
139
148
  .optional()
140
149
  .describe("New release date as ISO-8601 LocalDateTime"),
141
150
  isPublished: z.boolean().optional(),
151
+ isScheduled: z.boolean().optional().describe("Enable or cancel scheduled publication. Cannot be true with isPublished."),
142
152
  isActive: z.boolean().optional(),
143
153
  },
144
- }, async ({ id, titles, messages, releaseDate, isPublished, isActive }) => {
154
+ }, async ({ id, titles, messages, releaseDate, isPublished, isScheduled, isActive }) => {
145
155
  const client = getAdminClient();
146
156
  if (!client)
147
157
  return noAdminClientResponse();
148
158
  try {
159
+ if (isPublished && isScheduled) {
160
+ return errorResponse(new Error("isPublished and isScheduled cannot both be true"));
161
+ }
149
162
  const body = {};
150
163
  if (titles !== undefined)
151
164
  body.titles = titles;
@@ -155,6 +168,8 @@ export function registerAdminNewsTools(server) {
155
168
  body.releaseDate = releaseDate;
156
169
  if (isPublished !== undefined)
157
170
  body.isPublished = isPublished;
171
+ if (isScheduled !== undefined)
172
+ body.isScheduled = isScheduled;
158
173
  if (isActive !== undefined)
159
174
  body.isActive = isActive;
160
175
  const result = await client.put(`/api/v1/admin/news/${id}`, body);
@@ -1 +1 @@
1
- {"version":3,"file":"news.js","sourceRoot":"","sources":["../../../src/tools/admin/news.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"news.js","sourceRoot":"","sources":["../../../src/tools/admin/news.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "horizon-mcp",
3
- "version": "1.5.0",
4
- "description": "MCP server for horizOn Backend-as-a-Service — documentation, live API tools, and workflow prompts for Godot, Unity, and Unreal Engine integration.",
3
+ "version": "1.5.2",
4
+ "description": "MCP server for horizOn Backend-as-a-Service: documentation, live API tools, and workflow prompts for Godot, Unity, and Unreal Engine integration.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
7
7
  "bin": {
@@ -64,7 +64,7 @@ Content-Type: application/json
64
64
  |--------|-----|----------|
65
65
  | **Godot** | [horizOn SDK for Godot](https://github.com/ProjectMakersDE/horizOn-SDK-Godot) | GDScript |
66
66
  | **Unity** | [horizOn Cloud SDK for Unity](https://github.com/ProjectMakersDE/horizOn-SDK-Unity) | C# |
67
- | **Unreal Engine** | No official SDK | Use REST API directly (C++ FHttpModule or VaRest plugin) |
67
+ | **Unreal Engine** | [horizOn SDK for Unreal Engine](https://github.com/ProjectMakersDE/horizOn-SDK-Unreal) | C++ and Blueprints (Unreal Engine 5.5+) |
68
68
 
69
69
  ## Common HTTP Status Codes
70
70
 
@@ -2,432 +2,261 @@
2
2
 
3
3
  ## Overview
4
4
 
5
- There is **no official horizOn SDK for Unreal Engine**. Instead, you use the REST API directly via HTTP requests. This guide shows how to integrate horizOn using either:
5
+ horizOn has an **official Unreal Engine SDK**: the horizOn SDK plugin ([ProjectMakersDE/horizOn-SDK-Unreal](https://github.com/ProjectMakersDE/horizOn-SDK-Unreal)). It covers authentication, leaderboards, cloud save, remote config, localization, news, gift codes, feedback, user logs, crash reporting and email sending.
6
6
 
7
- - **VaRest Plugin** — Marketplace plugin for Blueprint-friendly HTTP requests
8
- - **FHttpModule** — Unreal's built-in C++ HTTP module
7
+ - **C++:** all features are reached through `UHorizonSubsystem`, a Game Instance Subsystem that owns one manager per feature (`Auth`, `Leaderboard`, `CloudSave`, `RemoteConfig`, `Localization`, `News`, `GiftCodes`, `Feedback`, `UserLogs`, `Crashes`, `EmailSending`).
8
+ - **Blueprints:** every call is also available as an async node with **On Success** and **On Failure** pins.
9
9
 
10
10
  ## Requirements
11
11
 
12
- - **Unreal Engine 5.x**
12
+ - **Unreal Engine 5.5** or later
13
13
  - horizOn API key (get one at [horizon.pm](https://horizon.pm))
14
- - HTTP request capability (VaRest plugin or FHttpModule)
14
+ - Target platforms declared by the plugin: Win64, Mac, Linux, Android, iOS
15
15
 
16
- ## API Configuration
16
+ ## Step 1: Install the Plugin
17
17
 
18
- All requests use these common settings:
18
+ 1. Download `horizOn-SDK-vX.Y.Z.zip` from [GitHub Releases](https://github.com/ProjectMakersDE/horizOn-SDK-Unreal/releases)
19
+ 2. Extract the `HorizonSDK/` folder into your project's `Plugins/` directory
20
+ 3. Open the project in Unreal Editor
21
+ 4. Go to **Edit > Plugins**, search for "horizOn SDK" and enable it
22
+ 5. Restart the editor when prompted
19
23
 
20
- | Setting | Value |
21
- |---------|-------|
22
- | Base URL | `https://horizon.pm` |
23
- | API Key Header | `X-API-Key: YOUR_API_KEY` |
24
- | Content Type | `Content-Type: application/json` |
25
- | Rate Limit | 10 requests/minute per client |
24
+ To call the SDK from C++, add `"HorizonSDK"` to the dependency module names in your game module's `.Build.cs`.
26
25
 
27
- ## Option A: VaRest Plugin (Blueprint-Friendly)
26
+ ## Step 2: Configure
28
27
 
29
- Install VaRest from the Unreal Marketplace, then use it in Blueprints or C++.
28
+ Open **Project Settings > Plugins > horizOn SDK**:
30
29
 
31
- ### C++ Setup with VaRest
30
+ | Option | Default | Description |
31
+ |--------|---------|-------------|
32
+ | API Key | (empty) | Your horizOn API key |
33
+ | Backend Hosts | (empty) | Backend URL(s), for example `https://horizon.pm`. One host connects directly, several hosts use ping-based selection. |
34
+ | Connection Timeout | 10 | HTTP request timeout in seconds |
35
+ | Max Retries | 3 | Retry count for failed requests |
36
+ | Retry Delay | 1.0 | Delay between retries in seconds |
37
+ | Log Level | Info | SDK log verbosity |
32
38
 
33
- ```cpp
34
- // MyHorizonManager.h
35
- #pragma once
36
- #include "CoreMinimal.h"
37
- #include "VaRestSubsystem.h"
39
+ Alternatively, use **Tools > horizOn > Import Config...** to import the JSON config file from the horizOn dashboard. The importer reads `apiKey` plus either `backendDomains` (list) or `backendUrl` (single host). `ConnectToServer()` fails with "No hosts configured" if Backend Hosts is empty.
38
40
 
39
- UCLASS()
40
- class UMyHorizonManager : public UObject
41
- {
42
- GENERATED_BODY()
41
+ ## Step 3: Connect to Server
43
42
 
44
- public:
45
- void SetApiKey(const FString& InApiKey) { ApiKey = InApiKey; }
43
+ ```cpp
44
+ // MyActor.h: connection handlers are bound to dynamic delegates, so declare them as UFUNCTION()
45
+ UFUNCTION()
46
+ void HandleConnected();
46
47
 
47
- void SignUpAnonymous(const FString& Username);
48
- void SubmitScore(const FString& UserId, int64 Score);
49
- void GetRemoteConfig(const FString& Key);
48
+ UFUNCTION()
49
+ void HandleConnectionFailed(const FString& ErrorMessage);
50
+ ```
50
51
 
51
- private:
52
- FString BaseUrl = TEXT("https://horizon.pm");
53
- FString ApiKey;
52
+ ```cpp
53
+ // MyActor.cpp
54
+ #include "HorizonSubsystem.h"
54
55
 
55
- UVaRestJsonObject* CreateRequestWithHeaders();
56
- };
57
- ```
56
+ void AMyActor::BeginPlay()
57
+ {
58
+ Super::BeginPlay();
58
59
 
59
- ## Option B: FHttpModule (Built-in C++)
60
+ UHorizonSubsystem* Horizon = GetGameInstance()->GetSubsystem<UHorizonSubsystem>();
61
+ Horizon->OnConnected.AddUniqueDynamic(this, &AMyActor::HandleConnected);
62
+ Horizon->OnConnectionFailed.AddUniqueDynamic(this, &AMyActor::HandleConnectionFailed);
63
+ Horizon->ConnectToServer();
64
+ }
65
+ ```
60
66
 
61
- No plugins required. Uses Unreal's native HTTP module.
67
+ Other connection calls: `Horizon->IsConnected()`, `Horizon->GetConnectionStatus()`, `Horizon->Disconnect()`.
62
68
 
63
- ### Base HTTP Helper
69
+ ## Step 4: Authenticate
64
70
 
65
71
  ```cpp
66
- // HorizonAPI.h
67
- #pragma once
68
- #include "CoreMinimal.h"
69
- #include "Http.h"
70
- #include "Json.h"
72
+ #include "Managers/HorizonAuthManager.h"
71
73
 
72
- class FHorizonAPI
74
+ void AMyActor::HandleConnected()
73
75
  {
74
- public:
75
- static FString BaseUrl;
76
- static FString ApiKey;
77
-
78
- // POST request helper
79
- static void Post(
80
- const FString& Endpoint,
81
- const TSharedRef<FJsonObject>& Body,
82
- TFunction<void(bool bSuccess, TSharedPtr<FJsonObject> Response)> Callback)
83
- {
84
- FHttpModule& Http = FHttpModule::Get();
85
- TSharedRef<IHttpRequest> Request = Http.CreateRequest();
86
-
87
- Request->SetURL(BaseUrl + Endpoint);
88
- Request->SetVerb(TEXT("POST"));
89
- Request->SetHeader(TEXT("Content-Type"), TEXT("application/json"));
90
- Request->SetHeader(TEXT("X-API-Key"), ApiKey);
91
-
92
- FString BodyString;
93
- TSharedRef<TJsonWriter<>> Writer = TJsonWriterFactory<>::Create(&BodyString);
94
- FJsonSerializer::Serialize(Body, Writer);
95
- Request->SetContentAsString(BodyString);
96
-
97
- Request->OnProcessRequestComplete().BindLambda(
98
- [Callback](FHttpRequestPtr Req, FHttpResponsePtr Resp, bool bConnected)
99
- {
100
- if (bConnected && Resp.IsValid() && Resp->GetResponseCode() == 200)
101
- {
102
- TSharedPtr<FJsonObject> JsonResponse;
103
- TSharedRef<TJsonReader<>> Reader = TJsonReaderFactory<>::Create(Resp->GetContentAsString());
104
- FJsonSerializer::Deserialize(Reader, JsonResponse);
105
- Callback(true, JsonResponse);
106
- }
107
- else
108
- {
109
- Callback(false, nullptr);
110
- }
111
- });
112
-
113
- Request->ProcessRequest();
114
- }
115
-
116
- // GET request helper
117
- static void Get(
118
- const FString& Endpoint,
119
- TFunction<void(bool bSuccess, TSharedPtr<FJsonObject> Response)> Callback)
76
+ UHorizonSubsystem* Horizon = GetGameInstance()->GetSubsystem<UHorizonSubsystem>();
77
+
78
+ // Anonymous sign-up (guest account)
79
+ Horizon->Auth->SignUpAnonymous(TEXT("Player1"), FOnAuthComplete::CreateLambda([Horizon](bool bSuccess)
120
80
  {
121
- FHttpModule& Http = FHttpModule::Get();
122
- TSharedRef<IHttpRequest> Request = Http.CreateRequest();
123
-
124
- Request->SetURL(BaseUrl + Endpoint);
125
- Request->SetVerb(TEXT("GET"));
126
- Request->SetHeader(TEXT("X-API-Key"), ApiKey);
127
-
128
- Request->OnProcessRequestComplete().BindLambda(
129
- [Callback](FHttpRequestPtr Req, FHttpResponsePtr Resp, bool bConnected)
130
- {
131
- if (bConnected && Resp.IsValid() && Resp->GetResponseCode() == 200)
132
- {
133
- TSharedPtr<FJsonObject> JsonResponse;
134
- TSharedRef<TJsonReader<>> Reader = TJsonReaderFactory<>::Create(Resp->GetContentAsString());
135
- FJsonSerializer::Deserialize(Reader, JsonResponse);
136
- Callback(true, JsonResponse);
137
- }
138
- else
139
- {
140
- Callback(false, nullptr);
141
- }
142
- });
143
-
144
- Request->ProcessRequest();
145
- }
146
- };
147
-
148
- // HorizonAPI.cpp
149
- FString FHorizonAPI::BaseUrl = TEXT("https://horizon.pm");
150
- FString FHorizonAPI::ApiKey = TEXT("");
81
+ if (bSuccess)
82
+ {
83
+ FHorizonUserData User = Horizon->Auth->GetCurrentUser();
84
+ UE_LOG(LogTemp, Log, TEXT("Signed in as %s (%s)"), *User.DisplayName, *User.UserId);
85
+ }
86
+ }));
87
+ }
151
88
  ```
152
89
 
153
- ## Feature Examples
154
-
155
- ### Anonymous Signup
90
+ ### Other Authentication Methods
156
91
 
157
92
  ```cpp
158
- void SignUpAnonymous(const FString& Username)
159
- {
160
- TSharedRef<FJsonObject> Body = MakeShared<FJsonObject>();
161
- Body->SetStringField(TEXT("type"), TEXT("ANONYMOUS"));
162
- Body->SetStringField(TEXT("username"), Username);
93
+ // Email sign-up and sign-in
94
+ Horizon->Auth->SignUpEmail(TEXT("user@example.com"), TEXT("password"), TEXT("Username"), FOnAuthComplete::CreateLambda([](bool bSuccess) { }));
95
+ Horizon->Auth->SignInEmail(TEXT("user@example.com"), TEXT("password"), FOnAuthComplete::CreateLambda([](bool bSuccess) { }));
163
96
 
164
- // Generate a unique anonymous token (max 32 chars)
165
- FString Token = FGuid::NewGuid().ToString(EGuidFormats::DigitsLower).Left(32);
166
- Body->SetStringField(TEXT("anonymousToken"), Token);
97
+ // Restore the cached anonymous session on the next launch
98
+ Horizon->Auth->RestoreAnonymousSession(FOnAuthComplete::CreateLambda([](bool bSuccess) { }));
167
99
 
168
- FHorizonAPI::Post(TEXT("/api/v1/app/user-management/signup"), Body,
169
- [](bool bSuccess, TSharedPtr<FJsonObject> Response)
170
- {
171
- if (bSuccess && Response.IsValid())
172
- {
173
- FString UserId = Response->GetStringField(TEXT("userId"));
174
- FString Name = Response->GetStringField(TEXT("username"));
175
- UE_LOG(LogTemp, Log, TEXT("Signed up: %s (%s)"), *Name, *UserId);
176
- }
177
- else
178
- {
179
- UE_LOG(LogTemp, Error, TEXT("Signup failed"));
180
- }
181
- });
182
- }
100
+ // Sign in with Apple (native sheet on iOS, system browser elsewhere)
101
+ Horizon->Auth->SignInWithApple(FOnAuthComplete::CreateLambda([](bool bSuccess) { }));
102
+
103
+ // Session state
104
+ bool bSignedIn = Horizon->Auth->IsSignedIn();
105
+ Horizon->Auth->SignOut();
183
106
  ```
184
107
 
185
- ### Email Sign-In
108
+ Google sign-in is available through `SignUpGoogle(AuthCode, RedirectUri, Username, OnComplete)` and `SignInGoogle(AuthCode, RedirectUri, OnComplete)`.
109
+
110
+ ## Step 5: Use Features
111
+
112
+ Each manager lives in `Managers/Horizon<Feature>Manager.h`. Include the header of the manager you call.
113
+
114
+ ### Leaderboards
186
115
 
187
116
  ```cpp
188
- void SignInEmail(const FString& Email, const FString& Password)
189
- {
190
- TSharedRef<FJsonObject> Body = MakeShared<FJsonObject>();
191
- Body->SetStringField(TEXT("type"), TEXT("EMAIL"));
192
- Body->SetStringField(TEXT("email"), Email);
193
- Body->SetStringField(TEXT("password"), Password);
117
+ // Submit a score (optional Metadata and BoardKey parameters follow the callback)
118
+ Horizon->Leaderboard->SubmitScore(12500, FOnRequestComplete::CreateLambda([](bool bSuccess, const FString& Error) { }));
194
119
 
195
- FHorizonAPI::Post(TEXT("/api/v1/app/user-management/signin"), Body,
196
- [](bool bSuccess, TSharedPtr<FJsonObject> Response)
120
+ // Top 10 entries (second argument: use the local cache)
121
+ Horizon->Leaderboard->GetTop(10, false, FOnLeaderboardEntriesComplete::CreateLambda(
122
+ [](bool bSuccess, const TArray<FHorizonLeaderboardEntry>& Entries)
123
+ {
124
+ for (const FHorizonLeaderboardEntry& Entry : Entries)
197
125
  {
198
- if (bSuccess && Response.IsValid())
199
- {
200
- FString Status = Response->GetStringField(TEXT("authStatus"));
201
- if (Status == TEXT("AUTHENTICATED"))
202
- {
203
- FString AccessToken = Response->GetStringField(TEXT("accessToken"));
204
- UE_LOG(LogTemp, Log, TEXT("Signed in successfully"));
205
- }
206
- }
207
- });
208
- }
126
+ UE_LOG(LogTemp, Log, TEXT("#%d %s: %lld"), Entry.Position, *Entry.Username, Entry.Score);
127
+ }
128
+ }));
129
+
130
+ // Own rank and the entries around it
131
+ Horizon->Leaderboard->GetRank(false, FOnLeaderboardRankComplete::CreateLambda([](bool bSuccess, const FHorizonLeaderboardEntry& Entry) { }));
132
+ Horizon->Leaderboard->GetAround(5, false, FOnLeaderboardEntriesComplete::CreateLambda([](bool bSuccess, const TArray<FHorizonLeaderboardEntry>& Entries) { }));
209
133
  ```
210
134
 
211
- ### Submit Leaderboard Score
135
+ ### Cloud Saves
212
136
 
213
137
  ```cpp
214
- void SubmitScore(const FString& UserId, int64 Score)
215
- {
216
- TSharedRef<FJsonObject> Body = MakeShared<FJsonObject>();
217
- Body->SetStringField(TEXT("userId"), UserId);
218
- Body->SetNumberField(TEXT("score"), Score);
138
+ Horizon->CloudSave->Save(TEXT("{\"level\": 5, \"coins\": 1000}"), FOnRequestComplete::CreateLambda([](bool bSuccess, const FString& Error) { }));
139
+ Horizon->CloudSave->Load(FOnStringComplete::CreateLambda([](bool bSuccess, const FString& Data) { }));
219
140
 
220
- FHorizonAPI::Post(TEXT("/api/v1/app/leaderboard/submit"), Body,
221
- [Score](bool bSuccess, TSharedPtr<FJsonObject> Response)
222
- {
223
- if (bSuccess)
224
- {
225
- UE_LOG(LogTemp, Log, TEXT("Score submitted: %lld"), Score);
226
- }
227
- });
228
- }
141
+ // Binary data
142
+ Horizon->CloudSave->SaveBytes(Bytes, FOnRequestComplete::CreateLambda([](bool bSuccess, const FString& Error) { }));
143
+ Horizon->CloudSave->LoadBytes(FOnBinaryComplete::CreateLambda([](bool bSuccess, const TArray<uint8>& Data) { }));
229
144
  ```
230
145
 
231
- ### Get Top Leaderboard
146
+ ### Remote Config
232
147
 
233
148
  ```cpp
234
- void GetTopLeaderboard(const FString& UserId, int32 Limit)
235
- {
236
- FString Endpoint = FString::Printf(
237
- TEXT("/api/v1/app/leaderboard/top?userId=%s&limit=%d"),
238
- *UserId, Limit);
149
+ // Typed getters with defaults (Key, Default, bUseCache, callback)
150
+ Horizon->RemoteConfig->GetString(TEXT("welcome_message"), TEXT("Welcome!"), true, FOnConfigComplete::CreateLambda([](bool bSuccess, const FString& Value) { }));
151
+ Horizon->RemoteConfig->GetInt(TEXT("max_level"), 100, true, TDelegate<void(bool, int32)>::CreateLambda([](bool bSuccess, int32 Value) { }));
239
152
 
240
- FHorizonAPI::Get(Endpoint,
241
- [](bool bSuccess, TSharedPtr<FJsonObject> Response)
242
- {
243
- if (bSuccess && Response.IsValid())
244
- {
245
- const TArray<TSharedPtr<FJsonValue>>* Entries;
246
- if (Response->TryGetArrayField(TEXT("entries"), Entries))
247
- {
248
- for (const auto& Entry : *Entries)
249
- {
250
- auto Obj = Entry->AsObject();
251
- int32 Position = Obj->GetIntegerField(TEXT("position"));
252
- FString Username = Obj->GetStringField(TEXT("username"));
253
- int64 Score = Obj->GetIntegerField(TEXT("score"));
254
- UE_LOG(LogTemp, Log, TEXT("#%d %s: %lld"), Position, *Username, Score);
255
- }
256
- }
257
- }
258
- });
259
- }
153
+ // All configs at once (recommended at startup)
154
+ Horizon->RemoteConfig->GetAllConfigs(true, FOnAllConfigsComplete::CreateLambda([](bool bSuccess, const TMap<FString, FString>& Configs) { }));
260
155
  ```
261
156
 
262
- ### Save and Load Cloud Data
157
+ `GetFloat`, `GetBool`, `GetJson` and `HasKey` follow the same pattern.
158
+
159
+ ### Localization
263
160
 
264
161
  ```cpp
265
- void SaveCloudData(const FString& UserId, const FString& SaveData)
266
- {
267
- TSharedRef<FJsonObject> Body = MakeShared<FJsonObject>();
268
- Body->SetStringField(TEXT("userId"), UserId);
269
- Body->SetStringField(TEXT("saveData"), SaveData);
162
+ // Active language: en, de, es, fr, it, pt, nl, pl, ru, ja, zh, ar, ko, tr, id
163
+ Horizon->Localization->SetLanguage(TEXT("de"));
270
164
 
271
- FHorizonAPI::Post(TEXT("/api/v1/app/cloud-save/save"), Body,
272
- [](bool bSuccess, TSharedPtr<FJsonObject> Response)
273
- {
274
- if (bSuccess && Response.IsValid())
275
- {
276
- bool Success = Response->GetBoolField(TEXT("success"));
277
- int32 Size = Response->GetIntegerField(TEXT("dataSizeBytes"));
278
- UE_LOG(LogTemp, Log, TEXT("Saved: %d bytes"), Size);
279
- }
280
- });
281
- }
165
+ // Empty language uses the active language
166
+ Horizon->Localization->GetLocalization(TEXT("welcome_message"), TEXT(""), FOnLocalizationComplete::CreateLambda([](bool bSuccess, const FString& Value) { }));
167
+ Horizon->Localization->GetAllLocalizations(TEXT("de"), FOnAllLocalizationsComplete::CreateLambda([](bool bSuccess, const TMap<FString, FString>& Translations) { }));
168
+ Horizon->Localization->GetAvailableLanguages(FOnLanguagesComplete::CreateLambda([](bool bSuccess, const TArray<FString>& Languages) { }));
169
+ ```
282
170
 
283
- void LoadCloudData(const FString& UserId)
284
- {
285
- TSharedRef<FJsonObject> Body = MakeShared<FJsonObject>();
286
- Body->SetStringField(TEXT("userId"), UserId);
171
+ ### News
287
172
 
288
- FHorizonAPI::Post(TEXT("/api/v1/app/cloud-save/load"), Body,
289
- [](bool bSuccess, TSharedPtr<FJsonObject> Response)
173
+ ```cpp
174
+ // Limit, language code, bUseCache, callback
175
+ Horizon->News->LoadNews(20, TEXT("en"), true, FOnNewsComplete::CreateLambda(
176
+ [](bool bSuccess, const TArray<FHorizonNewsEntry>& Entries)
177
+ {
178
+ for (const FHorizonNewsEntry& Entry : Entries)
290
179
  {
291
- if (bSuccess && Response.IsValid())
292
- {
293
- bool Found = Response->GetBoolField(TEXT("found"));
294
- if (Found)
295
- {
296
- FString Data = Response->GetStringField(TEXT("saveData"));
297
- UE_LOG(LogTemp, Log, TEXT("Loaded: %s"), *Data);
298
- }
299
- }
300
- });
301
- }
180
+ UE_LOG(LogTemp, Log, TEXT("%s: %s"), *Entry.Title, *Entry.Message);
181
+ }
182
+ }));
302
183
  ```
303
184
 
304
- ### Get Remote Config
185
+ ### Gift Codes
305
186
 
306
187
  ```cpp
307
- void GetAllRemoteConfigs()
308
- {
309
- FHorizonAPI::Get(TEXT("/api/v1/app/remote-config/all"),
310
- [](bool bSuccess, TSharedPtr<FJsonObject> Response)
311
- {
312
- if (bSuccess && Response.IsValid())
313
- {
314
- const TSharedPtr<FJsonObject>* Configs;
315
- if (Response->TryGetObjectField(TEXT("configs"), Configs))
316
- {
317
- for (const auto& Pair : (*Configs)->Values)
318
- {
319
- UE_LOG(LogTemp, Log, TEXT("Config: %s = %s"),
320
- *Pair.Key, *Pair.Value->AsString());
321
- }
322
- }
323
- }
324
- });
325
- }
188
+ Horizon->GiftCodes->Validate(TEXT("ABCD-1234"), FOnGiftCodeValidateComplete::CreateLambda([](bool bRequestSuccess, bool bValid) { }));
189
+ Horizon->GiftCodes->Redeem(TEXT("ABCD-1234"), FOnGiftCodeRedeemComplete::CreateLambda([](bool bSuccess, const FString& GiftData, const FString& Message) { }));
326
190
  ```
327
191
 
328
- ### Get Localizations
192
+ ### Feedback
329
193
 
330
194
  ```cpp
331
- // SetLanguage simply means appending ?lang=xx to the request (en, de, es,
332
- // fr, it, pt, nl, pl, ru, ja, zh, ar, ko, tr, id).
333
- void GetLocalization(const FString& Key, const FString& Lang)
334
- {
335
- FHorizonAPI::Get(FString::Printf(TEXT("/api/v1/app/localization/%s?lang=%s"), *Key, *Lang),
336
- [](bool bSuccess, TSharedPtr<FJsonObject> Response)
337
- {
338
- if (bSuccess && Response.IsValid() && Response->GetBoolField(TEXT("found")))
339
- {
340
- UE_LOG(LogTemp, Log, TEXT("Localization: %s"),
341
- *Response->GetStringField(TEXT("value")));
342
- }
343
- });
344
- }
195
+ Horizon->Feedback->ReportBug(TEXT("Crash on level 5"), TEXT("Game crashes when opening the inventory"), FOnRequestComplete::CreateLambda([](bool bSuccess, const FString& Error) { }));
196
+ Horizon->Feedback->RequestFeature(TEXT("Dark mode"), TEXT("Please add a dark mode option"), FOnRequestComplete::CreateLambda([](bool bSuccess, const FString& Error) { }));
197
+ ```
345
198
 
346
- void GetAllLocalizations(const FString& Lang)
347
- {
348
- FHorizonAPI::Get(FString::Printf(TEXT("/api/v1/app/localization/all?lang=%s"), *Lang),
349
- [](bool bSuccess, TSharedPtr<FJsonObject> Response)
350
- {
351
- if (bSuccess && Response.IsValid())
352
- {
353
- const TSharedPtr<FJsonObject>* Translations;
354
- if (Response->TryGetObjectField(TEXT("translations"), Translations))
355
- {
356
- for (const auto& Pair : (*Translations)->Values)
357
- {
358
- UE_LOG(LogTemp, Log, TEXT("Localization: %s = %s"),
359
- *Pair.Key, *Pair.Value->AsString());
360
- }
361
- }
362
- }
363
- });
364
- }
199
+ ### User Logs
200
+
201
+ ```cpp
202
+ // Requires BASIC tier or higher
203
+ Horizon->UserLogs->Info(TEXT("Tutorial completed"), FOnUserLogComplete::CreateLambda([](bool bSuccess, const FString& LogId, const FString& CreatedAt) { }));
365
204
  ```
366
205
 
367
- ## REST Examples (cURL)
368
-
369
- These cURL examples show the raw HTTP requests. Translate them to your preferred Unreal HTTP method.
370
-
371
- ```bash
372
- # Anonymous signup
373
- curl -X POST https://horizon.pm/api/v1/app/user-management/signup \
374
- -H "X-API-Key: YOUR_API_KEY" \
375
- -H "Content-Type: application/json" \
376
- -d '{"type": "ANONYMOUS", "username": "Player1", "anonymousToken": "unique32chartoken"}'
377
-
378
- # Submit score
379
- curl -X POST https://horizon.pm/api/v1/app/leaderboard/submit \
380
- -H "X-API-Key: YOUR_API_KEY" \
381
- -H "Content-Type: application/json" \
382
- -d '{"userId": "user123", "score": 12500}'
383
-
384
- # Get remote config
385
- curl "https://horizon.pm/api/v1/app/remote-config/all" \
386
- -H "X-API-Key: YOUR_API_KEY"
387
-
388
- # Get all localizations (German)
389
- curl "https://horizon.pm/api/v1/app/localization/all?lang=de" \
390
- -H "X-API-Key: YOUR_API_KEY"
391
-
392
- # Save cloud data
393
- curl -X POST https://horizon.pm/api/v1/app/cloud-save/save \
394
- -H "X-API-Key: YOUR_API_KEY" \
395
- -H "Content-Type: application/json" \
396
- -d '{"userId": "user123", "saveData": "{\"level\":5}"}'
397
-
398
- # Load cloud data
399
- curl -X POST https://horizon.pm/api/v1/app/cloud-save/load \
400
- -H "X-API-Key: YOUR_API_KEY" \
401
- -H "Content-Type: application/json" \
402
- -d '{"userId": "user123"}'
403
-
404
- # Get news
405
- curl "https://horizon.pm/api/v1/app/news?limit=10&languageCode=en" \
406
- -H "X-API-Key: YOUR_API_KEY"
407
-
408
- # Redeem gift code
409
- curl -X POST https://horizon.pm/api/v1/app/gift-codes/redeem \
410
- -H "X-API-Key: YOUR_API_KEY" \
411
- -H "Content-Type: application/json" \
412
- -d '{"code": "ABCD-1234", "userId": "user123"}'
413
-
414
- # Submit feedback
415
- curl -X POST https://horizon.pm/api/v1/app/user-feedback/submit \
416
- -H "X-API-Key: YOUR_API_KEY" \
417
- -H "Content-Type: application/json" \
418
- -d '{"title": "Bug Report", "message": "Description", "userId": "user123", "category": "BUG"}'
419
-
420
- # Create user log
421
- curl -X POST https://horizon.pm/api/v1/app/user-logs/create \
422
- -H "X-API-Key: YOUR_API_KEY" \
423
- -H "Content-Type: application/json" \
424
- -d '{"message": "Level complete", "type": "INFO", "userId": "user123"}'
206
+ `Warn` and `Error` take the same arguments. An optional error code can follow the callback.
207
+
208
+ ### Crash Reporting
209
+
210
+ ```cpp
211
+ // Automatic capture of engine errors (call once at game start)
212
+ Horizon->Crashes->StartCapture();
213
+
214
+ // Context for later reports
215
+ Horizon->Crashes->RecordBreadcrumb(TEXT("navigation"), TEXT("Entered level 5"));
216
+ Horizon->Crashes->SetCustomKey(TEXT("level"), TEXT("5"));
217
+
218
+ // Non-fatal exception
219
+ Horizon->Crashes->RecordException(TEXT("Failed to load texture"), TEXT("stack trace"));
425
220
  ```
426
221
 
427
- ## Best Practices for Unreal
222
+ ### Email Sending
223
+
224
+ ```cpp
225
+ TMap<FString, FString> Variables;
226
+ Variables.Add(TEXT("username"), TEXT("John"));
227
+
228
+ // UserId, template slug, variables, language, callback (an overload takes an ISO 8601 ScheduledAt before the callback)
229
+ Horizon->EmailSending->SendEmail(TEXT("user-uuid"), TEXT("welcome"), Variables, TEXT("en"),
230
+ FOnSendEmailComplete::CreateLambda([](bool bSuccess, const FSendEmailResponse& Response) { }));
231
+ ```
232
+
233
+ `CancelEmail(EmailId, ...)` and `GetEmailStatus(EmailId, ...)` manage emails that were already sent or scheduled.
234
+
235
+ ## Blueprints
236
+
237
+ Get the subsystem with the **Get HorizonSubsystem** node or use the async nodes directly. Examples of node names:
238
+
239
+ - **Connect to horizOn Server**
240
+ - **Sign Up Anonymous**, **Sign In Email**, **Restore Anonymous Session**, **Sign In With Apple (Native)**
241
+ - **Submit Leaderboard Score**, **Get Top Scores**, **Get Leaderboard Rank**
242
+ - **Cloud Save Data**, **Cloud Load Data**
243
+ - **Get Remote Config**, **Get All Remote Configs**, **Get Localization**, **Load News**
244
+ - **Validate Gift Code**, **Redeem Gift Code**, **Report Bug**, **Submit Feedback**
245
+ - **Record Exception**, **Report Crash**, **Send Email**
246
+
247
+ ## Hello horizOn Example
248
+
249
+ The plugin ships `AHelloHorizonActor`. Set the API key and Backend Hosts in Project Settings, drop the actor into a level and press Play. It connects, signs up anonymously, submits a leaderboard score and logs the result. Per-feature example actors (`AHorizonAuthExample`, `AHorizonLeaderboardExample`, `AHorizonCloudSaveExample` and others) live in `Source/HorizonSDK/Public/Examples/`.
250
+
251
+ ## Rate Limit Best Practices
252
+
253
+ All tiers are limited to **10 requests per minute per client**. The SDK retries HTTP 429 responses automatically.
254
+
255
+ - Load all remote configs and localizations once at startup
256
+ - Use the `bUseCache` parameters for leaderboards, remote config and news
257
+ - Submit scores only on improvement, not every frame
258
+ - Start crash capture once, not repeatedly
259
+
260
+ ## Without the Plugin
428
261
 
429
- - **Cache API key** — Store the API key in a config file or game settings, not hardcoded.
430
- - **Handle async properly** — All HTTP requests are asynchronous. Use delegates or lambdas for responses.
431
- - **Rate limit** — 10 requests/minute. Cache responses and batch operations.
432
- - **Error handling** — Always check HTTP status codes and handle 429 (rate limit) with exponential backoff.
433
- - **Store session tokens** — After sign-in, cache the `accessToken` and `userId` for subsequent requests.
262
+ The SDK is the recommended path. If you cannot use the plugin, the App API can be called directly over HTTP with the `X-API-Key` header. See the `horizon://api/reference` resource for all endpoints.