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