=== CashoutGuard ===
Contributors: cashoutguard
Tags: fraud, rewards, offerwall, security, multi-account
Requires at least: 6.0
Tested up to: 6.8
Requires PHP: 7.4
Stable tag: 1.1.0
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html

Fraud prevention for rewards, GPT and offerwall sites. It flags multi-accounts, VPNs, emulators and bots before you pay them.

== Description ==

[CashoutGuard](https://cashoutguard.com) scores each signup, login and cashout on your rewards site. It looks at device fingerprints, network intelligence (VPN, datacenter, Tor), automation and emulator signals, and links between accounts (shared devices, networks and payout addresses). Each check returns **allow**, **review** or **block**.

This plugin connects WordPress to CashoutGuard:

* It loads the CashoutGuard browser agent on every front-end page and on the login page, and keeps a short-lived `request_id` in the `cg_rid` cookie.
* Every self-service signup (`user_register`) and every login (`wp_login`) is scored. These checks never block users; the verdict is saved on the user.
* A **Risk** column on the Users screen shows each account's latest score and decision.
* Rewards and offerwall plugins can score cashouts, conversions and offer clicks through a small hook API (see below).
* It fails open. If CashoutGuard does not answer within 2 seconds, or answers with an error, the result is `allow`, so an outage never locks your users out or stops your payouts.

= External service =

This plugin sends data to the CashoutGuard API at `https://cashoutguard.com`, a third-party service. You need an account to use it.

* **In the browser:** the agent script `https://cashoutguard.com/v1/agent.js` sends device and browser characteristics to `https://cashoutguard.com/v1/collect`. This includes the user agent, screen, time zone, language, canvas, WebGL and audio hashes, and automation flags. As part of its WebRTC check it also contacts Google's public STUN server (`stun.l.google.com`). To tell people from scripts it counts clicks, key presses and pointer moves and their timing, but it never records which keys are typed, form fields or page content.
* **From your server:** on signup, login and cashout the plugin sends the WordPress user ID, the user's email, the visitor IP (`REMOTE_ADDR`) and the `request_id`. For cashouts it also sends the amount, the payout address and the payout method.

Terms of service: https://cashoutguard.com/terms
Privacy policy: https://cashoutguard.com/privacy

Mention CashoutGuard in your own privacy policy.

== Installation ==

1. Upload the `cashoutguard` folder to `/wp-content/plugins/`, or install the zip from **Plugins → Add New → Upload Plugin**.
2. Activate the plugin.
3. Open **Settings → CashoutGuard** and paste your public key (`pk_...`) and secret key (`sk_...`) from the CashoutGuard dashboard.
4. Leave your site in **monitor** mode in the CashoutGuard dashboard for a few days, check the Risk column and the dashboard, then switch to **enforce**.

== Hook API for rewards plugins ==

**Score an offerwall conversion (in your postback handler, after crediting the user):**

`
do_action( 'cashoutguard_conversion', $user_id, $amount, $offer_id, $transaction_id, 'cpx' ); // last: offerwall name
`

**Report a reversal or chargeback (in the offerwall's reversal postback, or once a day):**

`
do_action( 'cashoutguard_reversal', $transaction_id );              // one id or a list; 'valid' as 2nd argument to confirm
`

The Accuracy page then shows how much reversed money was flagged and which signals predict reversals on your users.

**Score a cashout and read the verdict:**

`
do_action( 'cashoutguard_cashout', $user_id, $amount, $payout_address, $method );
$decision = apply_filters( 'cashoutguard_cashout_decision', 'allow', $user_id ); // allow | review | block

if ( 'block' === $decision ) {
    // hold the cashout
} elseif ( 'review' === $decision ) {
    // queue it for manual review
} else {
    // pay
}
`

The filter returns the API's *action*. That is always `allow` in monitor mode, and it is also `allow` when CashoutGuard could not be reached. If the plugin is deactivated, the filter returns your default (`'allow'` in this example).

**Score any other event** (for example `conversion` in an offerwall postback, or `offer_click`):

`
if ( function_exists( 'cashoutguard_evaluate' ) ) {
    $risk = cashoutguard_evaluate( 'conversion', $user_id, array(
        'offer_id'       => $offer_id,
        'transaction_id' => $transaction_id,
        'amount'         => 0.40,
        'currency'       => 'USD',
    ) );
    // $risk = array( 'decision' => ..., 'action' => ..., 'score' => ..., 'reasons' => array(...), 'error' => null|string, 'raw' => array|null )
}
`

**Other hooks:**

* `cashoutguard_evaluated` (action) fires after every check with `( $result, $event, $user_id )`. Use it to log verdicts, or to act on them, for example logging out blocked users.
* `cashoutguard_evaluate_body` (filter) lets you change the request body before it is sent, for example to add `currency`.
* `cashoutguard_client_ip` (filter) sets the visitor IP. By default it is `REMOTE_ADDR`; change it when you are behind a proxy or CDN that you trust.
* `cashoutguard_base_url` (filter), or the `CASHOUTGUARD_BASE_URL` constant, sets the API origin. The default is `https://cashoutguard.com`.

== Frequently Asked Questions ==

= Does it block logins or registrations? =

No. Signups and logins are only scored and saved on the user. To act on them, hook into `cashoutguard_evaluated`. Blocking belongs in your cashout flow (see `cashoutguard_cashout_decision`).

= What happens if CashoutGuard is down? =

Each call has a 2-second timeout. On a timeout, a network error or any non-2xx answer, the result is `allow` and its `error` field says what went wrong.

= Where is the secret key stored? =

In the `cashoutguard_settings` option in your database. The settings page never prints it back; you only see a masked hint.

= Are accounts created by admins scored? =

No. Accounts created by a logged-in user (for example **Users → Add New**) are skipped, because the request would carry the admin's IP and device.

== Changelog ==

= 1.1.0 =
* Offerwall conversions (cashoutguard_conversion) and reversals or chargebacks (cashoutguard_reversal) through hooks.

= 1.0.0 =
* First release: browser agent, signup and login scoring, cashout hook API, Risk column on Users.
