Home/API Reference
Alpha status. Documented endpoints and request/response fields are additive-only and schema-stable: once listed in this reference, breaking changes ship with a 90-day deprecation window via 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

Go to Settings → API Keys, clickCreate API key, copy the 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.

TypeUse for
conversion_purchaseConfirmed sale — strongest positive signal
conversion_leadCaptured lead, form submit
conversion_signupAccount created
conversion_customIntegrator-defined positive outcome
engagement_positiveClick, reply, meaningful interaction
engagement_negativeUnsubscribe, bounce, rejection
thumbs_upExplicit positive feedback
thumbs_downExplicit 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 primitive
  • coppica_extract_copy — analyze arbitrary text, persist for learning
  • coppica_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

ScopeLimit (per key)Applies to
read120/hrGET endpoints
write30/hrPOST, PATCH, DELETE
execute10/hrBot runs
outcomes60/hrPOST /outcomes (higher for backfill bursts)
extract20/hrPOST /extract (Opus = expensive)

Also: per-output-per-key daily cap of 50 outcomes (protects the taxonomy from flooding).

Error codes

StatusMeaning
400Invalid request (bad UUID, missing field, out-of-range)
401Missing or invalid API key
403Wrong scope, client access denied, or spending cap exceeded
404Not found (also returned when access is denied)
429Rate limit exceeded. Check Retry-After header.
500Server error. Messages are sanitized.

All endpoints

Reference

GET
/bots

List available bot types with categories

GET
/me

Current user + credit balance

Clients

GET
/clients

List accessible clients

GET
/clients/{id}

Client detail + intake summary

Campaigns

GET
/clients/{id}/campaigns

List campaigns

GET
/clients/{id}/campaigns/{campaignId}

Campaign detail

POST
/clients/{id}/campaigns

Create campaign

Ideas

GET
/clients/{id}/ideas

List ideas

POST
/clients/{id}/ideas

Create idea

PATCH
/clients/{id}/ideas/{ideaId}

Edit or promote (body: { action: "promote" })

Tasks

GET
/clients/{id}/tasks

List tasks

POST
/clients/{id}/tasks

Create task

Bot Execution

POST
/clients/{id}/bots/{botType}/run

Trigger bot run (202 + poll_url)

GET
/jobs/{outputId}

Poll bot run status

Bot Outputs & Drafts

GET
/clients/{id}/outputs

List bot outputs

GET
/clients/{id}/outputs/{outputId}

Output detail

GET
/clients/{id}/drafts

List drafts

GET
/clients/{id}/drafts/{draftId}

Draft content

Learning Loop (Alpha)

POST
/extractflagship

Analyze arbitrary copy, extract techniques

POST
/outcomesflagship

Report conversion / engagement / feedback against output_id

GET
/clients/{id}/outcomes

Audit log of reported outcomes (scoped per-key)

Webhooks

GET
/webhooks

List webhook subscriptions

POST
/webhooks

Create a webhook

PATCH
/webhooks/{webhookId}

Update webhook

DELETE
/webhooks/{webhookId}

Delete webhook

Alpha support. Direct contact for Alpha integrators. Friction points get fixes within a week. Breaking changes, when unavoidable, ship with deprecation notices in Deprecation + Sunset HTTP headers and 90 days of notice.