Skip to main content
Training platforms hold some of the clearest evidence of champion engagement: courses finished, assessments passed, tournaments entered. This guide connects that activity to Katilyst so it earns recognition automatically. It uses Secure Code Warrior and Security Journey as the worked examples, and the approach applies to any platform that exposes an API. The two differ in one way that shapes the whole integration, which is where this starts.

Decide what you are rewarding

Both platforms expose several kinds of activity, and a program does not have to treat them alike. Finishing a single lesson and completing a full learning path represent different amounts of effort, and your Available Actions can reflect that.
Most programs start with one and add others as the program matures. Crediting both a lesson and the path it belongs to is a deliberate choice rather than a mistake — it rewards steady progress and completion separately — but decide it rather than discovering it.

Does your source support an incremental read?

This is the question that determines how your integration is built, and the answer depends on which endpoint you chose above. An incremental read means the API can return only what changed since you last asked. Where it exists, you pull a handful of records each run. Where it does not, you pull everything every time and sort it out yourself.

Yes — incremental

Pull only what changed, using the platform’s date parameter. Volume stays small and the ledger described below is a safety net rather than the mechanism.Security Journey /path-enrollments supports updated_after.Secure Code Warrior assessments and leaderboard support startdate and enddate.

No — full dump

Every call returns the complete history. You filter locally before doing anything expensive, and a ledger of what you have already credited becomes the integration rather than a convenience.Secure Code Warrior /learning/progress returns all completions for all developers on every call.Security Journey /lesson-attempts documents no filtering.
Note that Security Journey lands on both sides depending on what you reward. Crediting completed paths gives you an incremental read; crediting individual lessons does not. Same platform, same customer, two different implementations.
Check the current API reference for your platform before building. Date filtering tends to appear endpoint by endpoint rather than across an API, and parameters get added over time.

Connecting

Base URL: https://portal-api.securecodewarrior.com/api/v2European tenants use https://portal-api.eu.securecodewarrior.com/api/v2 instead. If you are not sure which applies, your Customer Success Manager can tell you.Authentication: an X-API-Key header carrying the token on its own, with no prefix.
Keys come in Report, Admin, and Team varieties, and each endpoint specifies which ones authorise it. A Report key is enough for everything in this guide.Pagination: responses carry a links object with total_pages and total_results. Compare total_results against what you actually received rather than assuming one call returned everything — /learning/progress serves 2000 records per page, so an organisation larger than that gets silently truncated.

Configure the action in Katilyst

1

Create an Available Action

Create an Instance action named for what it recognises — Secure Code Warrior — Module Completed, for example. Set the Attribute it changes, the amount, and any conditions.Create a separate action for each kind of activity you decided to reward. One for lessons and one for completed paths, if that is your model.
Use Instance actions here. Training completions are events that happened rather than states that persist. See Core concepts for the distinction.
2

Find your project ID

3

Find your action ID

Note the id for each action you created. You will need one per activity type.
Frequency limits configured on an Available Action do not apply to actions logged through the API. If a developer’s completion history is replayed, every record logs. The ledger described below is what prevents that, and it is your responsibility rather than Katilyst’s.

The pattern

Five stages, whatever you build this in.

Pull

Call the platform on a schedule. Daily is almost always enough — training completions arrive at human pace, and a tighter loop costs more for no benefit.If your endpoint supports an incremental read, pass a window slightly wider than your schedule interval. Two days against a daily run means a skipped or delayed run still catches its records.If it does not, you receive everything and move to the next stage.

Filter

Drop anything outside your window before doing anything else.This stage has to come first among the per-record steps. On a full-dump source it is the difference between examining a handful of records and examining thousands on every run. Filtering after a database lookup or an API call means paying for work you then discard.Use the completion timestamp the platform returns, and use the same wider-than-the-interval window as above. Overlap is safe because the next stage catches repeats.

Check the ledger

For each surviving record, ask whether you have credited this person for this item before.The ledger is a simple key-value store: a Make data store, a Zapier table, a database table, a file. The key identifies one person and one item — an email address and a course identifier, joined.Katilyst cannot do this for you. It records that an action was logged, not which course produced it, so two completions of different modules are indistinguishable to it. Without a ledger, every overlapping window credits the same work again.
Hash the key rather than concatenating raw values. Course identifiers can be long — Secure Code Warrior returns a five-level path that joins to over 150 characters — and a hash gives you a fixed-length key that cannot collide through accidental concatenation.

Log the action

For records not already in the ledger, call Katilyst.
Pass dateTime from the platform’s completion timestamp rather than letting Katilyst stamp on receipt. For a nightly job the two differ by hours, and reporting by period depends on the real date.Put something recognisable in creator, and the course name in details — that is what appears in the champion’s own activity log.

Record it

Write the key to the ledger, after the call succeeds.The ordering is deliberate. Writing first means a failed call permanently suppresses that credit with nobody noticing. Writing after means a successful call followed by a failed write credits again next run — visible in the champion’s log, and correctable.

Before the first live run: seed the ledger

On a full-dump source, skipping this step backfills everything. The first run sees every completion the platform has ever recorded, finds none of them in an empty ledger, and logs all of them. A developer who has been using the platform for two years collects two years of credit overnight, and the leaderboard stops meaning anything. Seed first:
  1. Run the integration with the Katilyst call disabled and the ledger write enabled.
  2. Remove the date filter so everything passes through.
  3. Let it complete. The ledger now holds every existing completion, marked as already credited.
  4. Re-enable the call and restore the filter.
From then on, only genuinely new completions are credited. To backfill deliberately — crediting the last quarter, say — seed with a filter that excludes that period, so those records stay absent from the ledger and get credited on the first live run.

Worked example: Secure Code Warrior via Make.com

One implementation of the pattern. The stages map onto any workflow tool; the module names are Make’s. Modules 6 and 9 share one key expression, which identifies a single person and a single course:
Four details that are easy to get wrong: Scope the inner iterator to the current developer. {{3.completed}} gives you that developer’s completions. Referencing the original response with empty brackets — {{2.data.developers[].completed}} — collects every completion by everyone, and each developer then gets credited for all of them. Put the date filter at module 5, before the data store lookup. Filters cost nothing in Make; data store operations do. In the wrong position it saves nothing. resource is an array, not a string. Secure Code Warrior returns a breadcrumb path. Use join() for both the ledger key and the details field. Handle 409 rather than failing on it. A 409 means that person is not eligible for the action, which happens routinely when someone outside the champion program completes training. Without an error handler, a few of them halt the run and every later record in that batch is lost. Attach a handler to module 8 that resumes on 409 and let other statuses fail normally. Set the scenario to process sequentially. Parallel execution lets two bundles both pass the ledger check before either writes.

Verify

  1. Two developers with multiple completions each. The only test that catches an incorrectly scoped iterator. Confirm each person is credited for their own work and nobody else’s.
  2. Run twice with no new activity. The second run should log nothing.
  3. Check your operation or task count on a quiet run. A number close to your developer count means the date filter is working. A number close to your total completion count means it is in the wrong place.
  4. Read an action back. Confirm actionDate matches the completion time rather than when the job ran, and that details reads as a course name.

Troubleshooting

  • Everyone is credited for everyone’s completions. The inner loop is reading the whole response rather than the current person’s records. This is invisible in a single-developer test.
  • The same completions are credited on every run. Either the ledger is never written, or nothing acts on the lookup result. Both halves are needed: a filter that stops already-credited records, and a write that records new ones.
  • The first run credited years of history. The ledger was not seeded. Credit can be removed in Katilyst, and seeding before the next run prevents a repeat.
  • Consumption is far higher than expected. The date filter is positioned after an operation that costs something. Move it ahead of the ledger lookup.
  • A 401 from the training platform. Secure Code Warrior wants X-API-Key with a bare token; Security Journey wants Authorization with a Bearer prefix. They are not interchangeable.
  • A 401 from Katilyst. The key is invalid, missing, or sent without the API-Key prefix on the header value.
  • A 409 from Katilyst. That person is not eligible for the Available Action. The request was well formed and the program’s own rules declined it.
  • Some developers are never credited. Check the platform’s pagination. Compare the total it reports against the number of records you received — a large organisation can exceed one page.

Core concepts

Instance versus State actions, guardrails, and how rewards are decided.

Log an action

Full reference for the endpoint this integration calls.