Skip to content
Open Portal

Serving Protocol

The wire contract every Appylar SDK speaks.

Applies to Appylar v1.0

The Appylar serving protocol is the wire contract every Appylar SDK speaks to the data-plane API — the same for the Android, iOS and Flutter SDKs today and for React Native, Unity and any future SDK. It is deliberately small, additive and versioned so it can grow for years without breaking older apps. This page is the canonical reference; the per-SDK guides (Android, iOS, Flutter) show how each one implements it.

The current protocol version is 1. Every SDK at v1.1.0 or later speaks it.

#Principles

  • Identical across SDKs. Same endpoints, same header names, same field names, same semantics. An SDK is a thin, faithful client of this protocol — it never invents its own dialect.
  • The SDK reports facts; the backend owns policy. The SDK sends what it reliably knows (the operating system it is running on) and what the developer explicitly declared (a non-default store). How those map to a store listing is decided server-side, so routing policy can change without shipping new SDKs.
  • Nothing derivable is sent. If the backend can determine something itself, the SDK does not send it.
  • Additive and backward compatible. New optional fields and new enum values never break older SDKs or older backends. Only a breaking change to existing semantics bumps the protocol version.

#Transport

  • HTTPS + JSON, under the API base https://api.appylar.com/v1. The /v1 is the API version (routes and resources); the protocol version below is a separate, finer-grained contract carried in a header.
  • Bearer auth: /token is exchanged for a short-lived serving token; sdk/config, serve and events send Authorization: Bearer <serving-token>.

#Headers

Every data-plane request (/token, /sdk/config, /serve, /events) carries:

HeaderExampleMeaning
Appylar-Protocol1The protocol version the SDK implements. Absent ⇒ treated as legacy (v0).
Appylar-SDKandroid-sdk/1.1.0SDK identity as <sdk>/<version>. sdkandroid-sdk, ios-sdk, flutter-sdk, react-native-sdk, unity-sdk, …

Appylar-SDK is how the backend observes which SDK and version is calling — without ever persisting that on the app. (An app's framework and SDK are not stored; they are observed here.)

The identifier always carries the -sdk suffix (flutter-sdk, not flutter). This names the official Appylar SDK implementation, keeping it unambiguous in logs, analytics and support: flutter-sdk is clearly the Appylar SDK rather than the Flutter framework, and it never collides with the runtime os values (android/ios) sent on /serve. New SDKs follow the same rule — react-native-sdk, unity-sdk.

#The /serve request

POST /v1/serve — the only request that carries serving inputs. All fields are optional on the wire (for backward compatibility); a protocol-v1 SDK always sends os.

{
  "device_id": "b1f2…",     // client-generated id for frequency capping
  "os": "android",           // runtime OS: "android" | "ios"
  "store": "amazon_appstore" // optional: explicit distribution store (see below)
}

#Fields — and why each exists

FieldRequiredWhy it existsWhy it can't be derived
device_idRecommendedFrequency capping per device/session.Generated on the client; the backend has no other stable per-device signal.
osSent by every v1 SDKThe primary store-routing signal, and a future hook for OS-specific formats/analytics.One app key is shared across OSes (a Flutter app is one app on both), so the backend cannot infer the OS from the token.
storeOptionalDeclares the exact store a build ships to when it isn't the OS default (Amazon Appstore, Huawei AppGallery, Samsung Galaxy Store…).A build/distribution fact known only to the developer; an "Android" build could come from any of several stores.

#Deliberately not in the protocol

Challenged and removed, because each is derivable or unused: device model, screen size, OS version, locale, network type, IP/geo (derived server-side), and the app's framework/SDK (observed via the Appylar-SDK header, not a body field). Adding any of these later is a purely additive change if a real need appears.

#Store routing

The backend resolves a served ad's click-through to a specific store listing using the hints above, in priority order:

  1. Explicit store — the listing for exactly that store, if the promoted app has one.
  2. OS default storeandroid → Google Play, ios → Apple App Store.
  3. OS-consistent listing — any listing whose store belongs to the viewer's OS (e.g. an Android viewer of an app listed only on Amazon).
  4. First listing — a deterministic fallback.
  5. None — if the app has no listings, the ad serves without a destination.

So the common case needs only os; store exists for the multi-store-per-OS world:

OSDefault storeOverride with store when the build ships to…
androidGoogle Playamazon_appstore, huawei_appgallery, samsung_galaxy_store
iosApple App Store(App Store is the only iOS store)

Because the OS→store default lives on the server, changing it never requires an SDK release.

#Versioning & extension

  • Version signal: the Appylar-Protocol integer header. This is v1.
  • Additive changes (no version bump): new optional request fields, new response fields, new store enum values. Old SDKs omit them; old backends ignore them.
  • Breaking changes (version bump): changing the meaning of an existing field, or making a field mandatory. The backend supports a window of versions; SDKs advertise theirs via the header so the backend can adapt.
  • Introspection: GET /v1/sdk/config returns protocol_version, so tools and SDKs can discover the backend's current version.

#Backward compatibility

  • Legacy SDKs (v1.0.0, pre-protocol). They send no protocol headers and only device_id. The backend treats a missing Appylar-Protocol as v0 and serves normally; store routing falls back to the app's first listing. Nothing breaks.
  • New SDK, old backend. The extra headers and fields are ignored by a backend that doesn't know them. Nothing breaks.
  • Guarantee: no field in this protocol is ever mandatory on the wire, so a correct request from any protocol version is always served.

#Implementation checklist (for a new SDK)

  1. Send Appylar-Protocol: 1 and Appylar-SDK: <platform>/<version> on every data-plane request.
  2. On /serve, send device_id, the runtime os, and store when the developer configured one.
  3. Expose an AppylarStore type (the five wire values) and an optional store on the SDK's config.
  4. Never send derivable/unused data.
  5. Add tests asserting the exact headers and serve body.