Skip to content

Pre-Launch Self-Test — v2/selfcheck (Handshake, Required)

Before the platform enables the v2 protocol for your merchant account, you must run the full encryption / signing / anti-replay pipeline end to end with selfcheck. This page explains what it does, how to call it, and how to get enabled once it passes.

Prerequisites: you have all 4 credentials (see Keys & Credentials) and have obtained an ANONY-TOKEN via getToken. For protocol details, see Encryption & Signing Protocol.

What It Does and How to Call It

Purpose: selfcheck is a read-only integration probe that lets you verify your SDK implements the full encryption / signing / anti-replay protocol correctly — before the platform flips the switch for your account.

Why it's required: going live is a one-shot cutover — once the platform enables v2 for your merchant account, every subsequent business request is immediately validated against this protocol. If your SDK has any mismatch at that point (OAEP hash, canonical string, signature algorithm), all requests will fail and your business will be interrupted. selfcheck lets you exercise the complete pipeline with real keys before the switch, so you can verify first, cut over second, with zero downtime.

What it verifies: the server runs your request through the full chain — token validation → timestamp/nonce anti-replay → SHA256 signature verification → OAEP decryption — then wraps the payload in the same v2 envelope and echoes it back verbatim. A single successful selfcheck therefore proves both directions: upstream (your encryption + signature is accepted by the server) and downstream (you can verify and decrypt the server's response).

POST /api/merchant/v2/selfcheck
Headers: ANONY-APP-ID / ANONY-TOKEN / ANONY-TIMESTAMP / ANONY-NONCE / ANONY-SIGN
Body: ciphertext of any business JSON (echoed back verbatim in the response's echo field)
  • The endpoint is read-only — it creates no orders or addresses and changes no state — so you can call it as many times as you like.
  • The response is a signed ciphertext envelope; once decrypted, data looks like { "pong": true, "apiVersion": 2, "serverTime": ..., "echo": <what you sent> }.
  • If your SDK can verify the signature, decrypt the payload, and retrieve echo, both directions of the pipeline are ready.
  • Once the self-test passes, notify the platform and they will complete the activation.

Response Fields (After Decryption)

FieldTypeDescription
pongboolAlways true; the server fully validated and processed your request
apiVersionintAlways 2; this request passed validation under the v2 protocol
serverTimeCurrent server time
echoYour request payload, echoed back verbatim

Use serverTime to check your clock

The v2 protocol's time window is ±5 minutes, and server clock drift is one of the most common causes of failure. Compare serverTime against your local clock: if the drift is close to or beyond 5 minutes, fix your NTP sync before continuing — otherwise business requests will be rejected with signatureFailed.

Example Calls

Calling selfcheck works exactly like any other business endpoint (encrypted body + the full set of signature headers) — just point it at v2/selfcheck:

php
require 'AnonyV2Client.php';
$client = new AnonyV2Client($appId, $serverPublicKeyB64, $merchantPrivateKeyB64);
$token  = $client->getToken($secret);  // handles md5 auth + signature verification + decryption to extract the token

$res = $client->post('v2/selfcheck', ['ping' => 'hello'], $token);
// $res['data'] is already verified and decrypted
// Expected: pong=true, apiVersion=2, echo matches what was sent
var_dump($res['data']['pong'], $res['data']['apiVersion'], $res['data']['echo']);
python
from anony_v2 import AnonyV2Client, auth_header
import requests

c = AnonyV2Client(app_id, server_pub_b64, merchant_priv_b64)

# Get the token first: the request is not encrypted, md5 auth only; the response still needs signature verification + decryption
tr = requests.post(c.base_url + "getToken",
                   headers={"ANONY-APP-ID": str(app_id), "Authorization": auth_header(app_id, secret)})
tb = tr.json()
token = c.verify_response(tb["data"], tr.headers["ANONY-TIMESTAMP"],
                          tr.headers["ANONY-NONCE"], tr.headers["ANONY-SIGN"])["token"]

req = c.build_request({"ping": "hello"}, token)
r = requests.post(c.base_url + "v2/selfcheck", data=req["body"], headers=req["headers"])
body = r.json()
if body["code"] == 10000:
    data = c.verify_response(body["data"], r.headers["ANONY-TIMESTAMP"],
                             r.headers["ANONY-NONCE"], r.headers["ANONY-SIGN"])
    assert data["pong"] is True and data["apiVersion"] == 2
    print(data["serverTime"], data["echo"])
js
const { AnonyV2Client } = require('./anony_v2');
const c = new AnonyV2Client(appId, serverPubB64, merchantPrivB64);
const token = await c.getToken(secret); // Node >=18: handles md5 auth + signature verification + decryption to extract the token

const req = c.buildRequest({ ping: 'hello' }, token);
const r = await fetch(c.baseUrl + 'v2/selfcheck', { method: 'POST', body: req.body, headers: req.headers });
const body = await r.json();
if (body.code === 10000) {
  const data = c.verifyResponse(body.data, r.headers.get('anony-timestamp'),
    r.headers.get('anony-nonce'), r.headers.get('anony-sign'));
  console.log(data.pong, data.apiVersion, data.serverTime, data.echo);
}

For Go / Java, where there is no high-level wrapper: build the request yourself using the SDK's Encrypt/Sign/Canonical/NewNonce (Go) or encrypt/sign/canonical/newNonce/buildHeaders (Java), POST it to v2/selfcheck, and process the response with Verify+Decrypt / verify+decrypt. See the SDK Guide for details.

Getting Enabled After the Self-Test Passes

Once the self-test succeeds (signature verifies, payload decrypts, echo matches what you sent), notify the platform and they will complete the activation.

Implementation detail: the switch is done manually by the platform — merchants cannot self-serve

  • Which protocol your merchant account is validated against is determined by the api_version recorded on the platform side. It is read exclusively from the platform side and cannot be specified or changed in a request (this prevents downgrade attacks).
  • After your self-test passes, platform operations staff manually switch your api_version to 2 — there is no self-service option; reach out via your integration group chat or a support ticket.
  • v2/selfcheck itself is always validated under v2 rules, regardless of your current api_version, so you can (and should) call it repeatedly before the official cutover.

Recommended sequence: get your SDK passing selfcheck → notify the platform to switch → immediately after the switch, call a business endpoint (e.g. merchantInfo) once more to confirm everything works.

Troubleshooting a Failed Self-Test

When selfcheck fails, it reports the same errors as business endpoints (e.g. signatureFailed, decryption failure, tokenExpired, IP whitelist Oops). Work through these in order:

  1. Confirm the OAEP hash is SHA-1 (the number one interop pitfall — many languages default to SHA-256);
  2. Confirm the canonical string is joined with \n in the order ts, nonce, body;
  3. Confirm the key roles: upstream requests are encrypted with the platform public key and signed with the merchant private key;
  4. Confirm your server clock is in sync (compare against the serverTime returned by this endpoint).

For the full reference, see Error Codes and Troubleshooting.