Start a Zama encryption job
Changed onStarts a background job that FHE-encrypts a campaign's leaderboard page and returns a job ID immediately. Poll GET /v4/confidential-rewards/zama/jobs/{jobId}; once status is completed, result holds the response described below. Encryption is too slow for one request, which is why it is a job.
The job ID is a hash of the request, so repeating a request joins the running or finished job instead of encrypting twice. A failed job is retried. Job state lives in Redis for 30 minutes.
The job's result is a campaign's leaderboard with every reward amount FHE-encrypted for Zama's confidential distribution: (recipient, encryptedAmount, inputProof) triples ready for FHE.fromExternal. Merkl performs the encryption, so the distributor never receives a cleartext amount.
Only amounts are confidential. Recipient addresses are returned in cleartext — the distributor must know who to pay. The participant set and count are therefore visible.
The proof binding is fixed by this route, not parameters. Every proof binds the campaign's reward-airdrop contract as both the consuming contract and the submitting msg.sender, alongside the chain ID and the chain's fhEVM ACL address. That address is the CREATE2 clone Zama's airdrop factory deploys for the onchain campaign ID, so it is known before deployment. Both are echoed back as contractAddress and userAddress. A proof cannot be rebound afterwards; it has to be re-encrypted.
One proof covers several recipients — recipientsPerProof (32 for euint64) entries share an inputProof, grouped by proofId. Submit a group together, or pass the same proof in each of several transactions; both verify.
Amounts must fit the FHE type. euint64 (the ERC-7984 type, and the default) caps one amount at 2^64-1, which is only ~18.44 tokens of an 18-decimal reward. Use amountDecimals to request a coarser denomination, or a wider fheType. The check covers the whole campaign, not the page: one overflowing amount fails every page with a 422 that carries a campaign-wide count, never a recipient or an amount. It never wraps.
Amounts are settled committed rewards, aggregated per recipient across reasons. Uncommitted engine state (TempLeaves) is excluded.
Private campaigns are refused. Campaigns that hide their leaderboard ARE served, to any caller with access to the campaign: the recipient list and count are cleartext by design, and no field reduces to one recipient's amount. truncatedDust, excludedZeroAmount and the overflow check are whole-campaign, never per page.
Results are ordered by recipient address, which is independent of the amounts — an amount-ordered response would reveal the full ranking even though every amount is encrypted. Not configurable, and it makes paging repeatable.
Request
- Base URL: https://api.merkl.xyz (the document declares no server; this is the origin it was published from)
- URL: https://api.merkl.xyz/v4/confidential-rewards/zama
- Auth: apiKey (a scheme the document does not define)
Query parameters
Onchain campaign ID (32-byte hex hash, e.g. 0x93cf385c...). NOT the internal Campaign.id.
If true, excludes the campaign creator, the Merkl multisig and the Merkl dumper.
Response
Response for status 200
Changes
- breaking
for the
queryrequest parameteritems, the max was decreased from1000.00to64.00
- breaking
- info
endpoint added
- info