Build
SurveyCTO guide
A form webhook posts each submission to a relay that rewards it.
How it fits together
SurveyCTO can post each submission to a URL, but it cannot sign a request the way Jusa's completions endpoint
wants or hold a secret key safely. So a small relay of yours sits between them: SurveyCTO posts to it, it checks the
post really came from your form, and it calls POST /rewards, keyed on the submission so each is paid
once, forever.
- Make a program (dashboard or
POST /programs) with the budget, the amount andper_recipient={"lifetime": 1}if each person is paid once. - Make a restricted key with only
rewards:write, and give it to the relay. If it ever leaks, it can reward from that program's budget and do nothing else. - Add a question for the respondent's mobile number to the form (and their meter, if you pay ZESA).
In SurveyCTO
- In your server console, set up a webhook for the form (SurveyCTO's data publishing to a URL),
pointing at your relay, for example
https://relay.example.org/surveycto?token=3f9c…. The long randomtokenin the URL is how the relay knows the post is yours. - Each submission arrives as JSON with your field names and SurveyCTO's own fields, among them
KEY(uuid:…), unique per submission. That is thecompletion_id. - Keep the phone field unencrypted, or the relay cannot read it.
The relay
@app.post("/surveycto") def surveycto(): if not hmac.compare_digest(request.args.get("token", ""), os.environ["RELAY_TOKEN"]): abort(403) s = request.get_json() submission = s["KEY"] # uuid:… jusa.Reward.create( program=os.environ["JUSA_PROGRAM"], recipient={"phone": s["phone"]}, completion_id=submission, idempotency_key=f"scto-{submission}", ) return "", 200
The same rules as any relay: a repeat is one reward, a refusal is final (answer 2xx), and an
unreachable Jusa is the only reason to answer 5xx.
Paying ZESA instead
Add a meter question and a token phone: recipient={"meter": s["meter"], "token_phone": s["phone"]}, and
let the program's choices include zesa. The meter is confirmed with ZESA before anything is
charged.