Use when staff search, filter, update, delete, or re-process existing academy FormEntry leads; do NOT use for creating leads, debugging storage_status failures, or public capture flows.
التثبيت
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
Use when staff search, filter, update, delete, or re-process existing academy FormEntry leads; do NOT use for creating leads, debugging storage_status failures, or public capture flows.
requires
["breathecode-staff-api-index"]
Skill: Manage FormEntry Leads (Staff)
When to Use
Use for searching, reading, updating, deleting, or re-processing existing academy FormEntry records.
Use for listing won deals (GET /v1/marketing/academy/lead/won).
When ActiveCampaign double sync is enabled, deal_status and ac_deal_* fields on GET may reflect salesperson CRM activity via reverse webhooks — not only staff PUT updates.
Staff PUT triggers form_entry.changed platform webhook but does not auto re-push to CRM. Use process to retry CRM sync.
Workflow
Set headers on all /academy/ routes: Authorization: Token <token>, Academy: <academy_id>, optional Accept-Language (en, es) for translated errors.
Search or list leads with filters (GET /v1/marketing/academy/lead). Use start and end for date windows on created_at. Save lead id values from results.
Get one lead by id (GET /v1/marketing/academy/lead/<id>). Use FormEntryBigSerializer response for full diagnostics (storage_status, storage_status_text, ac_contact_id, ac_deal_*, deal_status).
Update lead fields (PUT /v1/marketing/academy/lead/<id> or PUT /v1/marketing/academy/lead?id=<id>). Does not auto-call CRM. If storage_status=ERROR, fix fields then go to Step 5.
Re-process CRM sync (PUT /v1/marketing/academy/lead/process?id=<id>). Use after fixing data or for staff-created leads that were never processed. Add sync=true to process immediately and return storage_status in the response (default is async queue). See debug skill for when not to call process (DUPLICATED).
Delete leads in bulk (DELETE /v1/marketing/academy/lead?id=<id1>,<id2>). Requires id query param.
List won leads (GET /v1/marketing/academy/lead/won) with read_won_lead capability. Supports same date and filter params as the main list.
Endpoints
All endpoints below require Authorization, Academy, and optional Accept-Language. Paths contain /academy/.
Default: queues persist_single_lead per lead. sync=true processes inline and returns results.
List won leads
GET
/v1/marketing/academy/lead/won
read_won_lead
Filters deal_status=WON. Paginated.
List filters
Query param
Filters on
Notes
start
created_at >=
YYYY-MM-DD
end
created_at <=
YYYY-MM-DD at midnight start-of-day — use the next calendar day to include the full last day
storage_status
storage_status
e.g. ERROR, PENDING, PERSISTED, DUPLICATED
deal_status
deal_status
Uppercased in lookup (WON, LOST)
course
course
Comma-separated
location / location_alias
location
Comma-separated
deal_location
ac_deal_location
Comma-separated
deal_course
ac_deal_course
Comma-separated
ac_deal_id
ac_deal_id
Exact match
utm_medium
utm_medium
icontains
utm_url
utm_url
icontains
utm_campaign
utm_campaign
icontains
utm_source
utm_source
icontains
utm_term
utm_term
icontains
tags
tag slugs
Comma-separated
like
name search
Full-name fuzzy match
only_first
—
true returns first match only (hook-oriented shape)
limit, offset
pagination
Default limit 20
Example request — list leads by date and status
GET /v1/marketing/academy/lead?start=2026-04-01&end=2026-04-08&storage_status=ERROR&limit=20&offset=0
Authorization: Token <token>
Academy: 4
Example response — paginated list (subset)
{"count":3,"first":null,"next":null,"previous":null,"last":null,"results":[{"id":219384,"first_name":"Lucia","last_name":"Mendez","email":"lucia@example.com","phone":"+34600000000","course":"full-stack","location":"barcelona-spain","storage_status":"ERROR","storage_status_text":"You need to specify tags for this entry","deal_status":null,"created_at":"2026-04-03T15:29:11.532Z"}]}
Example request — get one lead
GET /v1/marketing/academy/lead/219384
Authorization: Token <token>
Academy: 4
Example response — single lead (subset)
{"id":219384,"first_name":"Lucia","last_name":"Mendez","email":"lucia@example.com","phone":"+34600000000","course":"full-stack","location":"barcelona-spain","tags":"website-lead","storage_status":"ERROR","storage_status_text":"You need to specify tags for this entry","ac_contact_id":null,"ac_deal_id":null,"deal_status":null,"won_at":null,"referral_key":"partner-acme-01","utm_source":"facebook","utm_campaign":"barcelona-bootcamp-q2","custom_fields":{},"created_at":"2026-04-03T15:29:11.532Z","updated_at":"2026-04-03T15:29:12.100Z"}
Example request — update lead (fix tags before retry)
PUT /v1/marketing/academy/lead/219384
Authorization: Token <token>
Academy: 4
Content-Type: application/json
{"tags":"website-lead","course":"full-stack"}
Example response — update
Same shape as get-one response with updated fields.
Query param
Notes
id
Required. Comma-separated lead ids.
sync
Optional. true, 1, or yes runs CRM sync inline instead of Celery queue. Response includes results with id, storage_status, storage_status_text per lead.
Example request — re-process CRM
PUT /v1/marketing/academy/lead/process?id=219384
Authorization: Token <token>
Academy: 4
Example response — process queued
{"details":"1 leads added to the processing queue"}
Poll GET /v1/marketing/academy/lead/219384 until storage_status is PERSISTED, DUPLICATED, or stable ERROR (skip polling when sync=true was used).
Example request — re-process CRM synchronously
PUT /v1/marketing/academy/lead/process?id=219384&sync=true
Authorization: Token <token>
Academy: 4