Skip to content

Quick Start

Welcome to Cowculator! This guide walks you through running your first battle in just a few minutes.

Send two fighter definitions to POST /api/battle/start, then use the returned battle result (BattleResult) to identify the winner or replay the battle from its battle log.

Looking for exact fields?

Use the OpenAPI reference for the complete request and response schemas, defaults, and validation rules.

Send a battle request

The request body has two fighters and optional battle configuration:

  • fighter_1 is the first fighter
  • fighter_2 is the second fighter
  • configuration controls the turn limit and its result policy

Skill arrays and the fallback skill are optional. The battle engine uses the fallback when a fighter has no active skill or cannot afford the next one. If no fallback exists, that turn ends without a skill.

Replace YOUR_API_KEY with your Cowculator API key, then run:

curl -X POST "https://api.cowculator.dev/api/battle/start" \
  -H "Content-Type: application/json" \
  -H "X-COW-Key: YOUR_API_KEY" \
  -d '{
    "fighter_1": {
      "fighter_id": "mighty-cow",
      "name": "Mighty Cow",
      "maximum_health": 1200,
      "initial_health": 1000,
      "maximum_energy": 40,
      "initial_energy": 40,
      "speed": 10,
      "defence": 0,
      "attack": 100,
      "critical_damage": 1.1,
      "critical_rate": 0,
      "critical_resistance": 0,
      "dot_reduction": 0,
      "damage_reduction": 0,
      "damage_multiplier": 1,
      "regeneration": {
        "health": [],
        "energy": []
      },
      "passive_skills": [],
      "active_skills": [
        {
          "skill_id": "headbutt",
          "name": "Headbutt",
          "chance": 1,
          "actions": [
            {
              "type": "attack",
              "name": "Headbutt hit",
              "chance": 1,
              "target_type": "enemy",
              "damage_value": 1.2,
              "damage_type": "normal"
            }
          ],
          "energy_cost": 20
        }
      ],
      "fallback_skill": {
        "skill_id": "cow-basic-attack",
        "name": "Basic Attack",
        "chance": 1,
        "actions": [
          {
            "type": "attack",
            "name": "Basic Attack hit",
            "chance": 1,
            "target_type": "enemy",
            "damage_value": 1,
            "damage_type": "normal"
          }
        ]
      }
    },
    "fighter_2": {
      "fighter_id": "wonder-dog",
      "name": "Wonder Dog",
      "maximum_health": 1000,
      "maximum_energy": 40,
      "speed": 12,
      "defence": 0,
      "attack": 90,
      "critical_damage": 1.1,
      "critical_rate": 0,
      "critical_resistance": 0,
      "dot_reduction": 0,
      "damage_reduction": 0,
      "damage_multiplier": 1,
      "regeneration": {
        "health": [],
        "energy": []
      },
      "passive_skills": [],
      "active_skills": [
        {
          "skill_id": "power-bite",
          "name": "Power Bite",
          "chance": 1,
          "actions": [
            {
              "type": "attack",
              "name": "Power Bite hit",
              "chance": 1,
              "target_type": "enemy",
              "damage_value": 1.2,
              "damage_type": "normal"
            }
          ],
          "energy_cost": 20
        }
      ],
      "fallback_skill": {
        "skill_id": "dog-basic-attack",
        "name": "Basic Attack",
        "chance": 1,
        "actions": [
          {
            "type": "attack",
            "name": "Basic Attack hit",
            "chance": 1,
            "target_type": "enemy",
            "damage_value": 1,
            "damage_type": "normal"
          }
        ]
      }
    },
    "configuration": {
      "max_turn": 40,
      "turn_limit_result": "remaining_health_percentage"
    }
  }'

This example shows the complete fighter, active-skill, and attack-action shapes. The API provides defaults for many of these fields, but keeping them visible makes the starting configuration clear. Add passive skill objects to passive_skills when your battle design needs them.

Try different outcomes

Change initial health, speed, attack, or damage_value, then send the request again. Cowculator preserves chance-based mechanics, so battles with chance values below 1 may play out differently.

Read the result

The response is a battle result represented by BattleResult. Start with these fields:

Field What it tells you
winner_id The ID of the winning fighter, or null for a draw
fighter_1_id, fighter_1_name The identity of the first fighter
fighter_2_id, fighter_2_name The identity of the second fighter
total_turn The number of global battle turns processed
battle_started When the battle started
battle_end When the battle ended
battle_event_logs The battle log used to inspect or replay the battle

The response always includes the battle log in battle_event_logs, with fighter snapshots and the events produced during the battle. See the BattleResult guide for its complete structure and examples.

Handle errors consistently

When a request fails, check its HTTP status and error code. See Error Handling for codes, examples, and the change from response.detail.

Explore what happened

Use winner_id when you only need the outcome. To build a replay, process battle_event_logs.preparation, battle_event_logs.turns, and battle_event_logs.battle_end in that order. Within each preparation entry or turn, read the ordered fighter events by event_type and structured data instead of parsing their display descriptions. For each turn, process its turn-level events first. Then process energy regeneration, health regeneration, and any natural status expiry in turn_end.events.

Next, learn how to: