Integration guide

For developers building on the ByteMaple license system: accounts, license keys, ad-free behaviour and push notifications.

The flow, in one paragraph

The user buys a package on this website (signing in with Google, paying with PayPal). The site issues a license key such as BM-K7QX2M-9FRT4A-ZP8W3D. Inside your app or program the user pastes that key; your code calls the activate endpoint once, then the verify endpoint on every start and once a day. While verify answers ad_free: true the app removes its ads; the moment it answers false (expired, revoked or over the device limit) the app shows ads again. The same package system covers three product types — games, apps and software — and a package can cover one or several of them, either every product of those types or a picked list.

1. Accounts: Google sign-in

Accounts live on this website only — apps never ask for a Google password. Send the user to https://bytemaple.com/login in a browser (or an in-app browser tab) to sign in, buy a package, and copy their key from https://bytemaple.com/account. Your app only ever handles the license key.

2. Entering a license key

Add a “Remove ads / I have a license key” screen in your settings. Ask for the key (accept any case, trim spaces), store it in your app's private storage, and call activate.

3. API: activate

POST https://bytemaple.com/api/license/activate — binds the key to this device for this app. Activations are counted per app: a key works on at most 3 devices in each app it covers, so the user's other apps never use up this app's slots. devices_used in the answers counts this app's activations only.

Request:

{
    "key": "BM-K7QX2M-9FRT4A-ZP8W3D",
    "app": "com.ludostrike.game",
    "device_id": "a1b2c3-install-uuid",
    "device_name": "DESKTOP-AB12CD",
    "platform": "android"
}

app is your product's package name (Windows: its slug works too). device_id is a stable id your app generates once per install and keeps. device_name is optional — a human-readable name for the device or computer (e.g. the Windows computer name); when sent it is stored on the activation and shown in the admin. Clients that omit it keep working unchanged. platform is android or windows.

Success — 200:

{
    "valid": true,
    "ad_free": true,
    "expires_at": "2027-01-26T10:00:00+00:00",
    "package_name": "com.ludostrike.game",
    "plan": "Ad-Free Monthly",
    "devices_used": 1,
    "devices_max": 3
}

Failure — 404/403 with { valid: false, ad_free: false, error, message }. Error codes: unknown_app, unknown_key, revoked, expired, not_covered (the package doesn't include this product), device_limit.

4. API: verify

POST https://bytemaple.com/api/license/verify with { key, app, device_id } (the optional device_name is accepted here too and refreshes the stored name). Always answers 200:

{
    "valid": true,
    "ad_free": true,
    "expires_at": "2027-01-26T10:00:00+00:00",
    "package_name": "com.ludostrike.game",
    "plan": "Ad-Free Monthly",
    "devices_used": 1,
    "devices_max": 3
}
  • When to call: on app start, then at least once a day while the app is used. Cache the last good answer for offline starts, but never for more than 24 hours.
  • ad_free: true → remove ads (next section). false → show ads again immediately. This is how an expired or refunded license returns ads on its own.
  • expires_at is null for lifetime keys.

5. API: deactivate

POST https://bytemaple.com/api/license/deactivate with { key, app, device_id } — releases this device's slot for this app, so the user can activate the app on another device. Answers 200 with { ok: true, deactivated: true }, or deactivated: false when this device had no activation for this app. Unknown apps/keys answer the same 404 shapes as activate. Users can also release any activation themselves from their account page on this website.

6. Ad-free behaviour in the app

  • Do not just hide the ad view — remove it from the layout (Android: View.GONE, never INVISIBLE; WPF/WinForms: Visibility.Collapsed). The empty ad slot must close up so the rest of the screen stretches and fits — no blank band where the banner was.
  • Stop requesting ads entirely while ad-free (no ad SDK calls in the background).
  • Rewarded options that ads unlock should stay reachable — grant them directly or leave a free button; never punish a paying user.
  • When verify flips back to ad_free: false, rebuild the ad container and resume normal ad loading.

Kotlin (Android) sketch

val body = JSONObject()
    .put("key", storedKey)
    .put("app", context.packageName)
    .put("device_id", installId)
    .put("platform", "android")

val res = postJson("https://bytemaple.com/api/license/verify", body)
if (res.optBoolean("ad_free")) {
    adContainer.removeAllViews()
    adContainer.visibility = View.GONE   // space collapses, layout refits
    adsEnabled = false
} else {
    adsEnabled = true                    // build the banner and load ads again
}

C# (Windows) sketch

var payload = new { key = storedKey, app = "ludo-strike", device_id = installId };
var res = await http.PostAsJsonAsync("https://bytemaple.com/api/license/verify", payload);
var state = await res.Content.ReadFromJsonAsync<VerifyState>();
AdBanner.Visibility = state.AdFree ? Visibility.Collapsed   // not Hidden
                                   : Visibility.Visible;

7. Push notifications

Register every install once (and whenever the push token changes):

POST https://bytemaple.com/api/devices/register

{
    "platform": "android",
    "app": "com.ludostrike.game",
    "install_id": "a1b2c3-install-uuid",
    "push_token": "fcm-token\u2026",
    "country": "IN"
}
  • Android: send the FCM token as push_token. Notifications arrive through Firebase with the campaign's title/body/image; a tap opens data.link_url when present — handle that key in your FCM service.
  • Windows: there is no push channel, so poll GET https://bytemaple.com/api/notifications?install_id=…&app=… on start (and at most hourly). Each campaign is returned once — the call itself marks it delivered. Show it as an in-app notice; open link_url in the browser on click.
  • country is the ISO 2-letter code, optional — used only for aggregate statistics.

8. Good practice

  • Never hard-code a license key in the app binary; keys belong to users.
  • Treat network failures as “keep the last known state”, not as “expired”.
  • Rate limits: the API allows 60 requests per minute per client — the cadence above is far below it.
  • Developers of a covered product can see the privacy wording for licenses and push on that product's privacy page, e.g. https://bytemaple.com/privacy/ludo-strike.