What you will accomplish
- Keep secrets and raw signatures out of Google Sheets
- Verify signed events before appending a row
- Reject replayed and duplicate events
- Compare sheet rows with Quote.Trade and your internal order log
Before you begin
- A server process that writes the review log
- A secret manager for the HMAC key
- A unique event ID for every record
- A restricted Google Sheet shared only with reviewers
Prices and order values are shown in USD. The collateral currency, such as USDC or USDT, and its blockchain network are separate settings. Check the live account and market settings for allowed currencies, minimum size, and leverage.
Choose the fields to include
Log only what is needed for review, such as event ID, request ID, Quote.Trade order ID, symbol, side, amount, approval time, submit time, and final result. Do not include API keys, signatures, wallet addresses, balances, or prompts.
Sign the record on your server
Serialize the JSON the same way on both sides, add issuedAt and a random nonce, then sign it with HMAC SHA256. Keep the signing key on the server, never in the AI client or the sheet.
import hashlib, hmac, json, time, secrets
def sign_event(event: dict, secret: bytes) -> tuple[str, str]:
event = {**event, 'issuedAt': int(time.time()), 'nonce': secrets.token_hex(16)}
body = json.dumps(event, separators=(',', ':'), sort_keys=True)
signature = hmac.new(secret, body.encode(), hashlib.sha256).hexdigest()
return body, signatureVerify the signature before writing the row
The receiving service should verify the timestamp, nonce, signature, and allowed fields before it writes anything to Google Sheets. Reject an expired, repeated, unsigned, or changed record.
Write from your server, not directly from the model
Only the verified server should append a row. The AI client should not hold the webhook secret or have direct write access to the sheet.
Compare the sheet with Quote.Trade order data
Periodically match each row to the Quote.Trade order ID and final result. Quote.Trade orders and account data determine what actually happened; the sheet is only a review log.
Common problems and fixes
Apps Script returns unauthorized
Confirm that both sides use the same HMAC key and the same JSON serialization. Then check the timestamp, nonce, signature header, and allowed fields.
Rows appear twice
Use eventId to ignore a record that has already been written. Keep the request ID and Quote.Trade order ID so duplicate or missing rows can be found later.
The sheet contains sensitive data
Disable the webhook, remove the exposed fields, rotate any affected credentials, and restrict sheet access before resuming.