> For the complete documentation index, see [llms.txt](https://merithic.gitbook.io/merithic-docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://merithic.gitbook.io/merithic-docs/api-reference/endpoints/verify-source.md).

# POST /verify-source

Checks that a script running in a buyer's game byte-for-byte matches the script of the same name inside your product's live version.

```
POST https://api.merithic.com/verify-source
```

This is the anti-tamper check. `/check` and `/unlock` prove *who* is running your product; this proves *what* they're running hasn't been edited.

{% hint style="info" %}
Turn on **Verify scripts** on the product's Settings tab first. With it off this endpoint always returns `ok: false`, regardless of the key.
{% endhint %}

## Request

| Field         | Type             | Required | Description                                  |
| ------------- | ---------------- | -------- | -------------------------------------------- |
| `user_id`     | string or number | yes      | The buyer's Roblox user ID.                  |
| `product_id`  | string           | yes      | Your product's ID.                           |
| `key`         | string           | yes      | The buyer's license key.                     |
| `script_name` | string           | yes      | The script's **Name** in the uploaded model. |
| `source`      | string           | yes      | The source currently running.                |

```json
{
  "user_id": "123456789",
  "product_id": "00000000-0000-0000-0000-000000000000",
  "key": "the buyer's key",
  "script_name": "Main",
  "source": "-- the running source"
}
```

`script_name` is the instance **Name**, not a path. It has to match a script Updatr parsed out of your live `.rbxmx` — the Files tab lists what was found.

## Response

```json
{ "ok": true }
```

`ok` is `true` only when every one of these holds:

* the product exists and has **Verify scripts** enabled,
* the user holds an **active** license for it,
* the key matches that license,
* the user isn't blacklisted by your studio, and
* `source` is byte-identical to the stored script.

Anything else returns `{ "ok": false }`. The endpoint deliberately never explains *which* check failed — that detail would tell someone probing it exactly what to fix.

## Exact means exact

The comparison is byte-for-byte. A changed comment, a trailing newline, or different indentation all fail.

That means a few ordinary things will trip it:

* **Obfuscation.** If the script is an [Obfuscator+](/merithic-docs/selling/obfuscator.md) target, what runs is the obfuscated build and won't match the stored source. Don't verify obfuscated scripts.
* **The license script.** Its placeholder is replaced with each buyer's key on download, so every copy differs. Don't verify it.
* **Editing after upload.** Fix the script, re-upload, and Sync — the check compares against the **live** version, not a draft.

## Alerts

A valid licensee whose source doesn't match raises a **stolen product** alert on your Alerts tab: they own a real license but are running modified code.

Two related alerts come from the same endpoint:

| Alert                     | What it means                                                                   |
| ------------------------- | ------------------------------------------------------------------------------- |
| `key_user_mismatch`       | The key belongs to a different account than `user_id` — a shared or lifted key. |
| `invalid_key_for_license` | The key doesn't match that user's license, or the license is paused.            |

## Example

{% tabs %}
{% tab title="Luau (server)" %}

```lua
local HttpService = game:GetService("HttpService")

local PRODUCT_ID = "00000000-0000-0000-0000-000000000000"
local USER_ID    = 1234567
local KEY        = "__UPDATR_LICENSE__"

-- The script checking ITSELF. `script.Source` is only readable from a plugin,
-- so in a normal game script you verify a ModuleScript you can read instead.
local function verifySelf(target: LuaSourceContainer): boolean
	local ok, res = pcall(function()
		return HttpService:RequestAsync({
			Url = "https://api.merithic.com/verify-source",
			Method = "POST",
			Headers = { ["Content-Type"] = "application/json" },
			Body = HttpService:JSONEncode({
				user_id     = USER_ID,
				product_id  = PRODUCT_ID,
				key         = KEY,
				script_name = target.Name,
				source      = (target :: any).Source,
			}),
		})
	end)
	if not ok or not res or not res.Success then
		-- Network trouble isn't proof of tampering. Fail OPEN here.
		return true
	end
	return HttpService:JSONDecode(res.Body).ok == true
end
```

{% endtab %}
{% endtabs %}

{% hint style="warning" %}
Fail **open** when the request itself errors. A buyer with a flaky connection shouldn't have your product stop working — the check is for catching tampering, not for gating normal startup. Use [`/unlock`](/merithic-docs/api-reference/endpoints/unlock.md) for the gate.
{% endhint %}

## See also

{% content-ref url="/pages/s4HsRum87vgVH4KC5lHW" %}
[POST /unlock](/merithic-docs/api-reference/endpoints/unlock.md)
{% endcontent-ref %}

{% content-ref url="/pages/f90FMPoRVaO9Wlfru9Sn" %}
[Integrating step by step](/merithic-docs/api-reference/integrating.md)
{% endcontent-ref %}


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://merithic.gitbook.io/merithic-docs/api-reference/endpoints/verify-source.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
