| Part | Where it is built |
|---|---|
| Collector, aggregation, deterministic identities | Your system |
| Reward calculation | A Code step in the workflow, or your own system before the event is sent |
| Ingest trigger, read step, router, bulk-update or write step | The API |
| Deploy, confirming a run, run reads | The API |
POST /{workflowId}/nodes and type: "code", with options.inputs bound to the row ({{<triggerId>.csv}}, {{<readStepId>.Total XP}}) and the source in options.sourceCode.code. Its result is keyed by the names it returns, so the bulk step references {{<codeStepId>.csv}}. It can be changed, duplicated, imported and tested like any other step, and a workflow containing it deploys normally.UNRESOLVED_SIMULATED_REFERENCE). Live-test the Code step on its own with a seed you chose, read the output, and only then dry-run the rest around it. Details are in the playbook Code steps through the API.GET /catalog returns platformActionFields.get and platformActionFields.post, each entry carrying the key the step stores, the label the platform stores beside it, and whether the field is builtin or custom.201, status: draft, trigger.type: event-ingest, the two paths stored under trigger.options, and a revision.trigger._id) is what the next steps reference. The production ingest id a sender needs is the trigger's id; give the sender that value, plus the endpoint it posts to.total_xp and total_coins are the read keys the catalog returns; a custom field would appear in the same list:xp is the write key from the catalog's post list. Two shapes are supported:post-user-fields, which is simple and needs no file:simulated with the resolved member, field and amount. sideEffects: "none" proves nothing was paid.simulated with its source and no output, and every step after it fails with UNRESOLVED_SIMULATED_REFERENCE. Test the Code step live on its own first, then read the trace here as evidence for everything around it.GET /{workflowId}/runs for the run, then GET /runs/{runId} for the per-step result.success on the run is not the reward. The member's field value, or the bulk job's per-row result, is the reward. Say "paid" only when you have one of those.| What you see | What it means | What to do |
|---|---|---|
| Ingest rejected with a batch id path message | The batch id was not at the configured path in the root of the event | Fix the sender's envelope; keep the same batch id only for a byte-identical retry. |
Ingest skipped | A duplicate batch id, or every row was a duplicate | Do not resend under a new batch id unless the data really is new. |
Run error | A step failed; the run detail names it | Fix the step, then decide about the batch. |
Run success, member unchanged | The reward step was skipped or the amount was zero | Read the run detail and the branch that ran. |
Bulk job Failed with every row success | The job failed as a whole; nothing was applied | Check the CSV header against the community's identifier field, then resend as a new batch. |
| Two awards for one row | The row reached the reward step twice | Fix the record id path or the sender's aggregation before the next cycle. |
recordIdPaths, a new batch to the same workflow only pays rows whose record ids are new (a duplicated workflow is a new workflow, so its first batch pays every row again), so correct an amount already paid through your approved correction or compensation path, as described in Trading volume and rewards.