fix(iab): correct Myket purchase verification to the documented POST /verify API
CI/CD / CI - API (dotnet build + engine sim) (push) Successful in 29s
CI/CD / CI - Web (tsc + next build) (push) Successful in 1m6s
CI/CD / Deploy - local stack (db + server + web) (push) Successful in 41s

Myket's server-to-server validation is POST
/api/partners/applications/{pkg}/purchases/products/{sku}/verify with the
purchase token in the JSON body ({"tokenId": ...}) + X-Access-Token header —
not a GET with the token in the path. purchaseState 0 = valid.
Ref: https://myket.ir/kb/pages/server-to-server-payment-validation-api/

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
soroush.asadi
2026-06-12 22:12:57 +03:30
parent 9cce016b90
commit 83d9c1c7d0
+11 -4
View File
@@ -110,19 +110,26 @@ public sealed class IabService
}
/// <summary>
/// Myket: validate via the developer API (mirrors Google Play). The access
/// token comes from the Myket developer panel.
/// Myket: validate via the developer API. POST the purchase token in the body
/// (`{ "tokenId": ... }`) to the partners/verify endpoint with an X-Access-Token
/// header. The access token comes from the Myket developer panel → in-app
/// products. See https://myket.ir/kb/pages/server-to-server-payment-validation-api/
/// </summary>
private async Task<bool> VerifyMyket(string productId, string token)
{
if (string.IsNullOrWhiteSpace(_opts.MyketAccessToken)) return _opts.AllowUnverified;
var url = $"https://developer.myket.ir/api/applications/{_opts.PackageName}/purchases/products/{Uri.EscapeDataString(productId)}/tokens/{Uri.EscapeDataString(token)}";
using var req = new HttpRequestMessage(HttpMethod.Get, url);
var url = $"https://developer.myket.ir/api/partners/applications/{_opts.PackageName}/purchases/products/{Uri.EscapeDataString(productId)}/verify";
using var req = new HttpRequestMessage(HttpMethod.Post, url);
req.Headers.Add("X-Access-Token", _opts.MyketAccessToken);
req.Content = new StringContent(
JsonSerializer.Serialize(new { tokenId = token }),
System.Text.Encoding.UTF8,
"application/json");
var resp = await Http.SendAsync(req);
if (!resp.IsSuccessStatusCode) return false;
using var doc = JsonDocument.Parse(await resp.Content.ReadAsStringAsync());
// purchaseState: 0 = successful purchase, 1 = failed.
if (doc.RootElement.TryGetProperty("purchaseState", out var ps) && ps.ValueKind == JsonValueKind.Number)
return ps.GetInt32() == 0;
return true;