Use when creating FormEntry leads via public capture, partner app, staff POST, or CSV bulk upload, including CRM and webhook side effects; do NOT use for listing, editing, deleting, or analyzing existing leads.
설치
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
Use when creating FormEntry leads via public capture, partner app, staff POST, or CSV bulk upload, including CRM and webhook side effects; do NOT use for listing, editing, deleting, or analyzing existing leads.
requires
["breathecode-staff-api-index"]
Skill: Create FormEntry Leads
When to Use
Use for POST /v1/marketing/lead*, POST /v2/marketing/lead*, POST /v1/marketing/app/lead, staff POST /v1/marketing/academy/lead, or bulk PUT /v1/marketing/academy/upload.
Use when explaining what happens after a lead is submitted (CRM queue, platform webhooks, storage_status).
Permissive serializer; email is the only business-mandatory field. An empty public POST can still return 201.
CRM process
Async persist_single_lead requires location, first_name, last_name, phone, course, and (for ActiveCampaign) tags or valid automations for successful CRM sync.
A lead can exist in the database with storage_status=ERROR even when create returned 201. Diagnose with the debug skill.
location and academy resolution
Routes the lead to an academy and CRM vendor via academy alias slugs and active_campaign_slug values.
Staff POST /v1/marketing/academy/leadoverrides any client location with the session academy's active_campaign_slug.
The canonical slug sent to CRM as utm_location may differ from the raw location when aliases are configured.
tags and automations
Comma-separated slugs, scoped to the academy's CRM configuration.
ActiveCampaign: tags are required unless automations is provided. Tag types must be STRONG, SOFT, DISCOVERY, or OTHER. Tags enroll contacts and can link to automations.
Brevo: tags are not supported. Only one automation slug is allowed.
Fallback: if automations is empty, the first tag's linked automation is used (ActiveCampaign only).
app/lead merges defaults from LeadGenerationApp before applying the request body.
Discover valid slugs: GET /v1/marketing/academy/tag, GET /v1/marketing/academy/automation.
referral_key
Capture-time marker (referrer, partner, influencer code) stored on FormEntry and forwarded to CRM.
Set at create time. Filterable on staff list (manage skill).
Not the same as affiliate commission payouts (/v1/commission/... — inbound skill).
custom_fields — why it exists
custom_fields is a JSON catch-all for partner-specific, campaign, or telemetry data that does not warrant a dedicated FormEntry column.
Many values are stored and forwarded (CRM, webhooks) but are not used for platform filtering or reporting logic.
Prefer custom_fields for new partner-specific or experimental capture data instead of proposing new schema columns.
First-class fields (utm_*, email, course, referral_key, deal_status, etc.) are reserved for values the platform filters, reports, or syncs with defined semantics.
On ActiveCampaign academies, numeric keys often map to CRM custom field ids; slug-key decoding on read is documented in the inbound skill.
Pass through unknown inbound keys into custom_fields rather than dropping them.
Other sensible create fields
utm_*, gclid (v1), ppc_tracking_id (v2), lead_type, language, course, phone, current_download, client_comments. lead_generation_app is set automatically on app/lead.
Create side effects
Side effect
Public / app / bulk CSV
Staff POST /academy/lead
form_entry.added platform webhook
Yes (on save)
Yes (on save)
CRM outbound (persist_single_lead)
Auto after save
No — call PUT .../lead/process via manage skill
Geolocation enrichment
After CRM if city missing
Same if processed
Initial storage_status
PENDING → PERSISTED / ERROR / DUPLICATED
Stays PENDING until process
CRM vendor routing (ACTIVE_CAMPAIGN vs BREVO) is automatic per academy CRM config (GET /v1/marketing/crmacademy).
Outbound CRM sync: create/process pushes leads to the CRM. Reverse sync (salesperson updates deal in ActiveCampaign reflected on FormEntry) is documented in bc-marketing-debug-form-entry.
Later platform webhook events (on update or deal change): form_entry.changed, form_entry.won_or_lost, form_entry.new_deal. Subscribe via POST /v1/notify/hook/subscribe (see HOOKS_MANAGEMENT.md).
Workflow
Set context headers. Staff and bulk paths require Authorization: Token <token> and Academy: <academy_id>. Send Accept-Language (e.g. en, es) for translated errors.
Pick the create path:
Public v1:POST /v1/marketing/lead or POST /v1/marketing/lead-captcha (uses gclid).
Public v2:POST /v2/marketing/lead or POST /v2/marketing/lead-captcha (uses ppc_tracking_id, not gclid).
Partner app:POST /v1/marketing/app/lead?app_id=<slug_or_token> — defaults merged from LeadGenerationApp.
Staff manual:POST /v1/marketing/academy/lead — then PUT /v1/marketing/academy/lead/process?id=<id> if CRM sync is needed (manage skill).
Bulk CSV:PUT /v1/marketing/academy/upload with multipart file.
Build the payload. Minimum: email. For successful CRM sync also include first_name, last_name, phone, course, location (except staff POST, which overrides location), tags or automations (per vendor rules), and attribution fields (utm_*, referral_key, custom_fields).
On 201, save the returned id. For public/app/bulk paths, CRM runs asynchronously. Poll with GET /v1/marketing/academy/lead/<id> (manage skill) or load the debug skill if storage_status is ERROR or stuck PENDING.
If integrations need real-time fan-out, confirm a form_entry.added hook subscription exists (POST /v1/notify/hook/subscribe).
POST /v1/marketing/app/lead?app_id=acme-partner merges LeadGenerationApp defaults (utm_*, location, language, tags, automations, academy) then overwrites with request body fields.
Each row runs asynchronously: save → persist_single_lead (auto CRM, same as public capture).
Current behavior: the bulk task maps first_name, last_name, email, location, academy only. Extra columns (referral_key, tags, utm_*) are not applied today.