Quickstart
From zero to a verified reward callback in about five minutes — set the URL, copy your secret, send a test callback, watch it land, then verify and reward.
This is the fastest path from "no callback" to "I just saw a signed heart.counted
hit my endpoint and verify cleanly." It's the smallest end-to-end slice — once it
works, the real integration is just granting the reward in step 6.
Set your callback URL
Open your server's dashboard → the Integration tab. In Reward callback URL
enter a public https:// endpoint, e.g.
https://your-server.example/mmolove/callback, and Save.
It must be a public HTTPS address — loopback / private / link-local URLs are rejected for SSRF safety.
Mint your signing secret
Click Rotate secret. The secret is shown once — copy it now and store it where your handler can read it (env var / secrets manager, never the browser or game client). Rotating again invalidates the previous secret immediately.
Drop in a handler
Grab the handler for your stack and wire in your SECRET:
PHP
Single-file drop-in — the classic vote-callback shape.
Node / JS
Express/Next handler, node:crypto.
Python
Flask/FastAPI, hmac + hashlib.
.NET / C#
Minimal API, HMACSHA256.
cURL
No framework — verify a captured callback from the shell.
The contract is just: read the raw body, recompute the MAC, compare it to the
X-MMOLove-Signature header, then reward.
Verify the signature
The MAC is HMAC_SHA256(secret, "<t>.<rawBody>") in lower-case hex, where t is
the t= field of the X-MMOLove-Signature header (it equals the body's
timestamp) and rawBody is the exact bytes you received.
<?php
$raw = file_get_contents('php://input'); // RAW body — read first
$header = $_SERVER['HTTP_X_MMOLOVE_SIGNATURE'] ?? '';
parse_str(str_replace(',', '&', $header), $sig); // t=..,v1=..
$expected = hash_hmac('sha256', $sig['t'] . '.' . $raw, $SECRET);
$ok = hash_equals($expected, $sig['v1'] ?? ''); // constant-timeSend a test callback and watch the log
On the Integration tab, click Send test callback. MMOLove signs a
heart.test payload with your current secret and POSTs it to your URL. A green
result (HTTP 2xx) means your endpoint received it and your signature check
passed.
Then look at the Delivery log on that same tab — real heart.counted
deliveries appear there with their status, HTTP code, attempt count, and time.
(The test callback is delivered live, so a successful one proves the loop.)
Grant the reward
On a verified heart.counted, look up username, grant the in-game reward
(scale it with streak_day if you like), and return a 2xx. Use heart_id as an
idempotency key so a retried delivery never double-rewards. Return non-2xx only
when you genuinely want MMOLove to retry.
What's next
Payload reference
Every field + heart.test + idempotency.
Signing & verification
The HMAC scheme in depth + replay window.
Errors, retries & delivery
Retry schedule + statuses + troubleshooting.
Handler guides
Complete copy-paste handlers.
Your signing secret is secret. Verify on your backend only — never ship it to a browser or game client.