Deprecation + Sunset HTTP headers. Undocumented or internal response fields (debug data, proprietary signal weights, implementation details) may change without notice while in Alpha — integrate only against what is documented here. Full GA commitments firm up as the API graduates from Alpha.Coppica API
Copy that learns what converts for your audience.
Most AI copy APIs generate. Coppica generates, tracks attribution, and updates its ~690-item persuasion taxonomy based on what actually converts — so the next generation for your audience is informed by real outcomes, not generic priors.
1. Generate your first piece of copy
Three calls from zero to your first piece of copy. Assumes you already have a client with at least some intake data populated.
1Create an API key
cpk_... value. Keys are shown once — store it now.2Pick a client and bot
# List clients you have access to curl https://coppica.com/api/v1/clients \ -H "Authorization: Bearer $COPPICA_API_KEY" # See available bots curl https://coppica.com/api/v1/bots -H "Authorization: Bearer $COPPICA_API_KEY"
3Run a bot, poll to completion
# Kick off a strategy bot
curl -X POST https://coppica.com/api/v1/clients/$CLIENT_ID/bots/PERSUASION_MAP/run \
-H "Authorization: Bearer $COPPICA_API_KEY" \
-H "Content-Type: application/json" \
-d '{}'
# Response: { "output_id": "...", "status": "processing" }
# Poll until status is "complete"
curl https://coppica.com/api/v1/jobs/$OUTPUT_ID \
-H "Authorization: Bearer $COPPICA_API_KEY"The completed response includes intake_completeness (fraction of the 15 intake fields populated) and warnings[] if intake is thin. Output quality improves when more intake fields are populated.
2. Close the loop
This is the primitive that makes Coppica different. When a conversion fires in your analytics (GA4, Stripe, your CRM, Cortana), tell Coppica — the Mimisbrunnr taxonomy weights update automatically for the persuasion techniques that output used.
Report an outcome
curl -X POST https://coppica.com/api/v1/outcomes \
-H "Authorization: Bearer $COPPICA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"output_id": "$OUTPUT_ID",
"type": "conversion_purchase",
"value": 127.00,
"external_id": "ga4-event-abc123"
}'Outcome types
Pick the type that matches what actually happened — Coppica's learning system weights each type differently based on how strong a signal it is. Report outcomes honestly; misreporting (e.g. logging every engagement as a purchase) poisons your own taxonomy since weights are scoped per-client.
| Type | Use for |
|---|---|
conversion_purchase | Confirmed sale — strongest positive signal |
conversion_lead | Captured lead, form submit |
conversion_signup | Account created |
conversion_custom | Integrator-defined positive outcome |
engagement_positive | Click, reply, meaningful interaction |
engagement_negative | Unsubscribe, bounce, rejection |
thumbs_up | Explicit positive feedback |
thumbs_down | Explicit negative feedback — strongest negative signal |
Idempotency
Pass your own event ID as external_id (GA4 event ID, Stripe payment intent, webhook delivery ID). Firing twice with the same (output_id, external_id) returns the existing outcome — safe for retryable webhook handlers.
Audit log
# See everything this API key has reported for a client curl https://coppica.com/api/v1/clients/$CLIENT_ID/outcomes \ -H "Authorization: Bearer $COPPICA_API_KEY"
Scoped per-key — you see only outcomes YOUR key reported, even if multiple keys share access to the same client.
When do weights actually update?
POST /outcomes returns immediately with weights_updated: 0 and weight_update_queued: true. The Bayesian weight update fires asynchronously within a few seconds. Weights activate for per-technique personalization at sample_count ≥ 10 per technique — so expect 4-8 weeks of outcomes before per-client personalization kicks in. To shortcut this, backfill existing copy + history (section 3).
3. Backfill existing copy (the on-ramp)
If you already have copy running somewhere (landing pages, historical ads, past emails) and have conversion history in GA4 / your CRM / Stripe, you can skip the cold-start entirely. Each piece of copy gets analyzed once, then you fire historical outcomes against the resulting output_ids — the taxonomy is tuned for your audience from day one.
Step 1: Extract techniques from your copy
curl -X POST https://coppica.com/api/v1/extract \
-H "Authorization: Bearer $COPPICA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"client_id": "$CLIENT_ID",
"text": "<your landing page copy>",
"label": "Landing page v3 hero",
"persist": true
}'Response includes an output_id + the extracted techniques. Withpersist: true (default), Coppica stores a bot_outputs row so you can later fire outcomes against this output_id. Set persist: false for one-off analysis (competitor audits, anti-slop scoring) where you don't need persistence.
Step 2: Fire historical outcomes
Map conversions from your analytics to the output_id above, then fire POST /outcomes for each. Historicaloccurred_at timestamps are supported up to 1 year back.
curl -X POST https://coppica.com/api/v1/outcomes \
-H "Authorization: Bearer $COPPICA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"output_id": "$EXTRACTED_OUTPUT_ID",
"type": "conversion_purchase",
"value": 99.00,
"occurred_at": "2026-03-15T10:23:00Z",
"external_id": "ga4-event-xyz"
}'Cost
Extraction uses Opus (~$0.05-0.20 per call depending on length). Outcome reporting is free. For a backfill of 100 pieces of copy + thousands of historical outcomes, expect $5-20 in extraction costs — recovered many times over if the resulting weights improve conversion rates even slightly.
4. Integrate with your existing analytics
You own the attribution. Coppica doesn't need to generate tracking links or manage UTMs — just tell us what output_id converted and we update the weights.
Meta Ads → Coppica
Encode the output_id in your UTM parameters when deploying copy (e.g.utm_content=$OUTPUT_ID). Your webhook handler or Meta Conversions API integration:
// In your webhook handler
async function handleMetaConversion(event) {
const outputId = parseOutputIdFromUtm(event.utm_content)
if (!outputId) return
await fetch(`https://coppica.com/api/v1/outcomes`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.COPPICA_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
output_id: outputId,
type: event.event_name === 'Purchase' ? 'conversion_purchase' : 'conversion_lead',
value: event.value,
external_id: event.event_id,
occurred_at: event.event_time,
}),
})
}Cortana → Coppica
When Cortana fires an attribution webhook, your handler maps its payload to a Coppica output_id(using your own tracking-link mapping) and POSTs to /outcomes. Cortana-specific webhook receivers aren't needed — the generic /outcomes endpoint handles it.
GA4 → Coppica
Daily GA4 export → parse events with UTM content pointing to Coppica outputs → batch-fire /outcomes. Use external_id (the GA4 event ID) for idempotency so reruns don't double-count.
Zapier / Make
Trigger: any event from your source analytics. Action: Webhook POST to https://coppica.com/api/v1/outcomeswith the Bearer header and the structured body.
5. MCP for agents
If your agent supports MCP, skip the REST calls and use intent-shaped tools. The MCP server wraps the REST API with 25 tools: 4 intent-shaped (recommended) + 21 CRUD.
Recommended intent tools
coppica_write_copy— generate copy in one call (built-in polling up to 90s)coppica_report_outcome— flagship feedback primitivecoppica_extract_copy— analyze arbitrary text, persist for learningcoppica_get_client_context— batched snapshot for agent onboarding
Local (stdio) — Claude Desktop / Claude Code
{
"mcpServers": {
"coppica": {
"command": "node",
"args": ["/path/to/coppica/mcp-server/dist/index.js"],
"env": {
"COPPICA_API_KEY": "cpk_...",
"COPPICA_API_BASE": "https://coppica.com/api/v1"
}
}
}
}Remote (HTTP) — for VPS-hosted agents
Run the HTTP variant on your own server. Each MCP request authenticates per-request via theAuthorization header — fully multi-tenant, no shared key.
PORT=3001 COPPICA_API_BASE=https://coppica.com/api/v1 \ node /path/to/mcp-server/dist/http-server.js # Connect from your remote agent: # POST https://your-vps.example.com/mcp # Authorization: Bearer cpk_...
6. Reference
Authentication
Every request includes Authorization: Bearer cpk_.... Missing or disabled keys return 401. Keys carry three scopes (read, write,execute) — all keys have all three by default.
Rate limits
| Scope | Limit (per key) | Applies to |
|---|---|---|
read | 120/hr | GET endpoints |
write | 30/hr | POST, PATCH, DELETE |
execute | 10/hr | Bot runs |
outcomes | 60/hr | POST /outcomes (higher for backfill bursts) |
extract | 20/hr | POST /extract (Opus = expensive) |
Also: per-output-per-key daily cap of 50 outcomes (protects the taxonomy from flooding).
Error codes
| Status | Meaning |
|---|---|
| 400 | Invalid request (bad UUID, missing field, out-of-range) |
| 401 | Missing or invalid API key |
| 403 | Wrong scope, client access denied, or spending cap exceeded |
| 404 | Not found (also returned when access is denied) |
| 429 | Rate limit exceeded. Check Retry-After header. |
| 500 | Server error. Messages are sanitized. |
All endpoints
Reference
/botsList available bot types with categories
/meCurrent user + credit balance
Clients
/clientsList accessible clients
/clients/{id}Client detail + intake summary
Campaigns
/clients/{id}/campaignsList campaigns
/clients/{id}/campaigns/{campaignId}Campaign detail
/clients/{id}/campaignsCreate campaign
Ideas
/clients/{id}/ideasList ideas
/clients/{id}/ideasCreate idea
/clients/{id}/ideas/{ideaId}Edit or promote (body: { action: "promote" })
Tasks
/clients/{id}/tasksList tasks
/clients/{id}/tasksCreate task
Bot Execution
/clients/{id}/bots/{botType}/runTrigger bot run (202 + poll_url)
/jobs/{outputId}Poll bot run status
Bot Outputs & Drafts
/clients/{id}/outputsList bot outputs
/clients/{id}/outputs/{outputId}Output detail
/clients/{id}/draftsList drafts
/clients/{id}/drafts/{draftId}Draft content
Learning Loop (Alpha)
/extractflagshipAnalyze arbitrary copy, extract techniques
/outcomesflagshipReport conversion / engagement / feedback against output_id
/clients/{id}/outcomesAudit log of reported outcomes (scoped per-key)
Webhooks
/webhooksList webhook subscriptions
/webhooksCreate a webhook
/webhooks/{webhookId}Update webhook
/webhooks/{webhookId}Delete webhook
Deprecation + Sunset HTTP headers and 90 days of notice.