Gamification Developer Documentation

Every REST endpoint, action, and filter the plugin ships, on one page. Examples are live against Gamification Plugin Showcase, so the URLs and IDs match what you're integrating with.

Authentication

Every request needs a Bearer token. You can create API Bearer Tokens on the API tab of the Gamification settings page; the full value only shows up once at generation time, so copy it right then.

Tokens go in the Authorization header. We don't accept them in the query string; that's a tripwire for leaking credentials into server access logs.

curl -H 'Authorization: Bearer mcgf_8a3f2b1c...' \
  'https://wlm-ronald.apps.cspf.co/wp-json/mcgf/v1/me'

Pick the smallest scope set that lets your integration do its job. We check on every request.

  • points:read
  • points:write
  • achievements:read
  • ranks:read
  • leaderboard:read

Points

GET /users/{id}/points

Required scope: points:read

A user's current balance. One integer, ready to drop straight into a UI.

Parameters

Name In Type Description
id path integer WordPress user ID.

Example request

curl -H 'Authorization: Bearer mcgf_8a3f2b1c...' \
  'https://wlm-ronald.apps.cspf.co/wp-json/mcgf/v1/users/42/points'

Example response

{
  "user_id": 42,
  "balance": 1750
}

Errors

  • 404 mcgf_api_user_not_found: User does not exist.

POST /users/{id}/points/award

Required scope: points:write

Award points. Routes through PointsEngine like an internal call, so the trigger's rate limit and any disabled-trigger checks still apply. The API isn't a back door around them.

Parameters

Name In Type Description
id path integer WordPress user ID.
amount body integer Non-negative point amount.
trigger_type body string Trigger key (sluggified).
trigger_id body integer Optional related object ID.
description body string Optional human description.

Example request

curl -X POST 'https://wlm-ronald.apps.cspf.co/wp-json/mcgf/v1/users/42/points/award' \
  -H 'Authorization: Bearer mcgf_8a3f2b1c...' \
  -H 'Content-Type: application/json' \
  -d '{"amount":50,"trigger_type":"course_completed","description":"Finished course #7"}'

Example response

{
  "transaction_id": 1234,
  "transaction": { "id": 1234, "user_id": 42, "amount": 50, "trigger_type": "course_completed", "description": "[API: Zapier] Finished course #7", "admin_id": 0, "created_at": "2026-04-25 14:32:00" },
  "user_id": 42,
  "balance": 1800
}

Errors

  • 422 mcgf_api_rate_limited: Trigger rate-limit blocks this award.
  • 422 mcgf_api_invalid_param: Validation failed on a body field.

GET /users/{id}/points/history

Required scope: points:read

Paginated transaction history for a single user. Defaults to 20 per page, newest first.

Parameters

Name In Type Description
id path integer WordPress user ID.
page query integer 1-based page number.
per_page query integer Page size (max 100).
date_from query string Y-m-d lower bound.
date_to query string Y-m-d upper bound.

Example request

curl -H 'Authorization: Bearer mcgf_8a3f2b1c...' \
  'https://wlm-ronald.apps.cspf.co/wp-json/mcgf/v1/users/42/points/history?page=1&per_page=20'

Example response

{
  "items": [ { "id": 1234, "amount": 50, "trigger_type": "course_completed" } ],
  "total": 12,
  "pages": 1,
  "page": 1,
  "per_page": 20
}

GET /points/transactions

Required scope: points:read

The full transaction log across every user. Filter by user, trigger, or date when you don't want to scroll past everything.

Parameters

Name In Type Description
user_id query integer Optional user filter.
trigger_type query string Optional trigger filter.
date_from query string Y-m-d lower bound.
date_to query string Y-m-d upper bound.
page query integer 1-based page number.
per_page query integer Page size (max 100).

Example request

curl -H 'Authorization: Bearer mcgf_8a3f2b1c...' \
  'https://wlm-ronald.apps.cspf.co/wp-json/mcgf/v1/points/transactions?user_id=42&per_page=10'

Example response

{ "items": [ /* tx rows */ ], "total": 0, "pages": 1, "page": 1, "per_page": 10 }

POST /users/{id}/points/deduct

Required scope: points:write

Take points away from a user. The request fails outright if the balance would go negative; we never let a user owe points.

Parameters

Name In Type Description
id path integer WordPress user ID.
amount body integer Positive integer.
trigger_type body string Trigger key.
trigger_id body integer Optional related object ID.
description body string Optional description.

Example request

curl -X POST 'https://wlm-ronald.apps.cspf.co/wp-json/mcgf/v1/users/42/points/deduct' \
  -H 'Authorization: Bearer mcgf_8a3f2b1c...' \
  -H 'Content-Type: application/json' \
  -d '{"amount":100,"trigger_type":"redeem"}'

Example response

{ "transaction_id": 1235, "balance": 1700, "user_id": 42 }

Errors

  • 422 mcgf_api_insufficient_balance: Balance too low.

POST /users/{id}/points/adjust

Required scope: points:write

Signed manual adjustment with a reason field. Positive or negative, no rate limit. The transaction is stored as admin_id=0 with the calling token's label prepended to the description, so the audit log can tell API edits apart from human ones.

Parameters

Name In Type Description
id path integer WordPress user ID.
amount body integer Non-zero integer (positive or negative).
reason body string Human-readable reason.

Example request

curl -X POST 'https://wlm-ronald.apps.cspf.co/wp-json/mcgf/v1/users/42/points/adjust' \
  -H 'Authorization: Bearer mcgf_8a3f2b1c...' \
  -H 'Content-Type: application/json' \
  -d '{"amount":-25,"reason":"Refund for failed delivery"}'

Example response

{ "transaction_id": 1236, "balance": 1675, "user_id": 42 }

Errors

  • 422 mcgf_api_invalid_param: amount is zero or missing.
  • 422 mcgf_api_insufficient_balance: Negative adjustment exceeds balance.

Achievements

Auto and hidden achievements are awarded by the engine. Manual achievements are only awarded by an admin from the WordPress user-profile screen.

GET /achievements

Required scope: achievements:read

Every published achievement. Filter by mode when you only care about, say, the manual ones an admin awards by hand.

Parameters

Name In Type Description
mode query string Optional mode filter.
page query integer 1-based page number.
per_page query integer Page size (max 100).

Example request

curl -H 'Authorization: Bearer mcgf_8a3f2b1c...' 'https://wlm-ronald.apps.cspf.co/wp-json/mcgf/v1/achievements'

Example response

{ "items": [ { "id": 7, "title": "First Lesson", "mode": "auto", "badge_url": "..." } ], "total": 1, "pages": 1, "page": 1, "per_page": 20 }

GET /achievements/{id}

Required scope: achievements:read

One achievement by ID. Returns 404 for unpublished or deleted achievements; published is the only public state we expose.

Parameters

Name In Type Description
id path integer Achievement post ID.

Example request

curl -H 'Authorization: Bearer mcgf_8a3f2b1c...' 'https://wlm-ronald.apps.cspf.co/wp-json/mcgf/v1/achievements/7'

Example response

{ "id": 7, "title": "First Lesson", "mode": "auto", "badge_url": "...", "requirements": [{"trigger":"lesson_completed","count":1,"target_id":0}] }

Errors

  • 404 mcgf_api_not_found: Achievement not published or does not exist.

GET /users/{id}/achievements

Required scope: achievements:read

What this user has actually unlocked, with the date each badge was earned.

Parameters

Name In Type Description
id path integer WordPress user ID.

Example request

curl -H 'Authorization: Bearer mcgf_8a3f2b1c...' 'https://wlm-ronald.apps.cspf.co/wp-json/mcgf/v1/users/42/achievements'

Example response

{ "items": [ { "achievement_id": 7, "title": "First Lesson", "awarded_at": "2026-04-25T14:32:00Z" } ] }

Errors

  • 404 mcgf_api_user_not_found: User does not exist.

Ranks

GET /ranks

Required scope: ranks:read

Every published rank, low to high by points_required. Use this to render a ladder.

Example request

curl -H 'Authorization: Bearer mcgf_8a3f2b1c...' 'https://wlm-ronald.apps.cspf.co/wp-json/mcgf/v1/ranks'

Example response

{ "items": [ { "id": 11, "title": "Bronze", "points_required": 100, "position": 1 } ] }

GET /ranks/{id}

Required scope: ranks:read

One rank, by ID. Same shape as an entry in the list response.

Parameters

Name In Type Description
id path integer Rank post ID.

Example request

curl -H 'Authorization: Bearer mcgf_8a3f2b1c...' 'https://wlm-ronald.apps.cspf.co/wp-json/mcgf/v1/ranks/11'

Example response

{ "id": 11, "title": "Bronze", "points_required": 100, "position": 1 }

Errors

  • 404 mcgf_api_not_found: Rank not published or does not exist.

GET /users/{id}/rank

Required scope: ranks:read

Where this user stands on the ladder: current rank, next rank, and how many points are still in their way. points_to_next is 0 once they're at the top.

Parameters

Name In Type Description
id path integer WordPress user ID.

Example request

curl -H 'Authorization: Bearer mcgf_8a3f2b1c...' 'https://wlm-ronald.apps.cspf.co/wp-json/mcgf/v1/users/42/rank'

Example response

{ "current": { "id": 11, "title": "Bronze" }, "next": { "id": 12, "title": "Silver", "points_required": 500 }, "points_to_next": 300 }

Errors

  • 404 mcgf_api_user_not_found: User does not exist.

Leaderboard

Leaderboard data is cached for 5 minutes.

GET /leaderboard

Required scope: leaderboard:read

Top scorers for a given timeframe. Cached for 5 minutes per (tab, limit) pair, so a busy site doesn't hammer the DB. Users who opted out of leaderboards are excluded automatically.

Parameters

Name In Type Description
tab query string daily, weekly, monthly, or all_time.
limit query integer 1 to 100 (default 10).

Example request

curl -H 'Authorization: Bearer mcgf_8a3f2b1c...' 'https://wlm-ronald.apps.cspf.co/wp-json/mcgf/v1/leaderboard?tab=monthly&limit=10'

Example response

{ "tab": "monthly", "limit": 10, "items": [ { "rank": 1, "user_id": 42, "display_name": "Alice", "points": 1750 } ] }

Errors

Errors come back in the standard WP REST envelope, with our own `code` slugs so you can branch on what actually went wrong rather than parsing English:

{ "code": "mcgf_api_invalid_token", "message": "Invalid API token.", "data": { "status": 401 } }
Status Code Meaning
401mcgf_api_missing_tokenAuthorization header missing or malformed.
401mcgf_api_invalid_tokenBearer value does not match any active token.
401mcgf_api_token_expiredToken expired before this request.
403mcgf_api_insufficient_scopeToken does not include the required scope.
404mcgf_api_user_not_foundPath user ID does not exist.
404mcgf_api_not_foundResource (achievement, rank) not found or unpublished.
422mcgf_api_invalid_paramValidation failed; data.params lists fields.
422mcgf_api_rate_limitedAward rejected by the trigger's rate limit.
422mcgf_api_insufficient_balanceDeduction would push the balance below zero.
500mcgf_api_internalUnhandled server error.