# Indie Exchange 0.4: simple setup and server fraud controls

## Developer setup

Add the game on the website, paste its Game ID in Unity, and enable Test Mode while testing. No certificate fingerprint, service account, Google project or App Attest entitlement is required. USB-installed Android builds work. The package does not change Android minimum SDK or iOS entitlements. Your ordinary platform signing/build requirements are unchanged.

Test Mode in the Unity Editor uses offline sample ads and makes no server requests. On a device, Test Mode with a Game ID uses real active server creatives. The server keeps preview sessions separate from live sessions and never issues preview impression tickets. Preview cannot create production serves, impressions, clicks, statistics or wallet entries. An empty Game ID uses an offline sample.

## Deploying the service

Publish the updated IndieExchange.Web MVC project to IIS and update the Unity package together. The existing PostgreSQL connection and strong Jwt:Key are sufficient for installation delivery. SdkSecurity:Enabled controls only the older v2 platform-attestation endpoints; it can remain false. No Google credentials or signing certificates are needed for v3.

InstallationDeliveryEnabled defaults to true; the operator can disable it under SdkSecurity as an emergency stop. Startup adds StandardAutoApproveCredits to the identity table with a false default, preserving existing data and keeping existing attested approval separate.

Games appear in Administration → App identities on first launch. Eligible traffic settles automatically, including traffic from new publishers. Administration → Traffic alerts contains only events held by integrity findings or unusual installation, network, publisher, or credit volume. These signals need investigation and are not proof of fraud. Disable delivery to suspend an abusive game; re-enrollment never re-enables it. The old trust switches no longer control settlement.

Country comes from the connection IP, never a client country field. Optionally configure SdkSecurity:GeoIpDatabaseFile with a maintained GeoIP database. Without it, country is ZZ and the configured fallback country rate applies; an unavailable country lookup is not an abuse signal. Personal-only opportunities are zero-credit and can settle without country verification. Public-to-personal fallbacks that earn credits use the same automatic settlement and abuse checks as public ads. Configure only exact trusted reverse proxy IPs if applicable; never trust arbitrary forwarded headers.

## Protection and its limits

The SDK automatically creates a per-installation RSA signing key in its app-private storage. It signs a short-lived server challenge bound to the exact operation and payload. Challenges are one-use and IP-bound. Live and preview installation/session namespaces are separate. Server-derived ad tickets expire in five minutes, are bound to the installation and game, and cannot settle twice. Premature claims fail. Limits apply to installation, network and publisher; wallet/budget/credit-ceiling checks run again in a serialized transaction at settlement.

These signatures prevent replay and unauthorized use of another installation’s tickets. They do not prove a physical device, actual viewing, or app ownership. A determined attacker can create keys or modify a client. Game IDs are public; never use them as secrets or reward raw request counts. Review flagged traffic and suspend abusive accounts. All traffic remains subject to limits; no client-only approach eliminates fraud.

The old v2 attestation backend remains available for existing advanced integrations, with its stricter checks unchanged. The 0.4 Unity package uses v3 installation signatures and does not invoke platform attestation.


## Live request cooldown (0.4.1)

The server allows one live ad-selection attempt every 30 seconds per game installation and ad format. Banner and interstitial loads have independent deadlines; public/personal categories share a deadline. A no-fill result still consumes the interval. Reinitializing, changing campaigns, or restarting IIS does not reset it. The deadline uses PostgreSQL time and an atomic update, including across server replicas. Requests rejected during cooldown create no ad serves, impression tickets or credits.

HTTP 429 includes Retry-After. The SDK pauses both category loads for that format and retries automatically; cached ads and your existing provider remain available. Initial public/personal preloading can take more than one interval. Test previews are exempt from this cooldown because they never affect production accounting; their existing abuse limits still apply.

The operator may set SdkSecurity:AdRequestCooldownSeconds (default 30, enforced range 1–3600) in server configuration. No developer setup changes are required. This identifies a persisted installation key, not an immutable physical device: reinstalling/clearing data can create another key. Network and publisher limits, one-use tickets, and credit review still apply. Client-reported opportunity counters are diagnostics, not credited impressions.

## Public no-fill accounting (0.5.3)

`Exchange:PublicNoFillRewardsEnabled` defaults to true. A public selection that cannot find inventory may supply a linked personal backup using the same request/cooldown and impression ticket. Its ticket records the fallback on the server and quotes country weight × media multiplier × publisher earn ratio. The personal advertiser is not debited. Rewarded personal backups require completed playback before settlement.

If no creative can be supplied and the SDK declares receipt support, the server issues a no-fill opportunity ticket at the lowest enabled media rate for the requested format. It creates no serve or impression. The SDK claims it through the signed `opportunity` action only when a normal public slot is consumed. Background requests, client statistics and preview calls never grant credits. Repeated claims are idempotent. Disable the option to stop issuing new incentive quotes; already-issued quotes remain valid until expiry.

Paid public fallbacks and empty opportunities settle automatically using the same country rates, installation/network limits and daily credit ceiling as public impressions. Only integrity findings and traffic/credit limits create Pending alerts. Developer pages show flagged amounts and reasons; operators handle them under Administration → Traffic alerts. Approval grants credits once. An unavailable country lookup or an ordinary mobile network switch does not require review.

Startup adds three ticket columns with false/zero defaults. Publish Web before upgrading the SDK. Older clients can display server-supplied personal backups but do not receive no-creative receipts. SDK 0.5.3 works with older servers, with the old credit behavior until the server is updated.

## Automatic credits and old routine holds

Normal traffic requires no administrator approval. The service rechecks old Pending tickets whose only recorded reason was a new publisher, unavailable country lookup, or a mobile network change. Rechecking is bounded, restart-safe and serialized with claims/reviews. It applies claim-volume limits for the original day and current settlement eligibility and credit ceilings. Existing integrity/volume alerts, manually annotated holds and settled zero-credit impressions are not automatically cleared or reclassified. Country lookup failures use the ZZ rate. Signatures establish installation continuity, not proof of a real device; automatic settlement does not eliminate fraud.

Creative moderation is separate: Administration → Review ads shows every submitted public image/video with its copy and destination. Approve or Reject directly in the list. Rejection uses a default explanation if no optional note is supplied. The content fingerprint still prevents approving an outdated preview, and every decision is recorded. Personal-only ads do not enter this queue.
