Skip to content
Contractsv1.7.0

AI Generated Contracts

The web editor can build a contract from a plain-English description, using your own LLM (ChatGPT, Claude, etc.). There is no API key to set up and nothing to pay beyond the subscription you already have: you copy a prompt, paste it into your chat, and paste the model’s reply back into the editor, which validates it, matches up item names, and shows a preview before anything is saved.

  1. Open the editor and click Generate on the contracts list.
  2. Describe the contract you want, then click Copy prompt. That copies the authoring instructions plus your description to the clipboard.
  3. Paste it into your LLM and send.
  4. Copy the model’s reply, paste it into the editor’s second box, and click Preview contract. Review the preview, then Use this contract.

You can paste the whole reply, prose and code fences and all. The editor reads only the JSON contract out of it.

If you author contracts often, seed the prompt below into a reusable assistant once, then just chat with it and paste the JSON it returns straight into the editor’s second box.

  • Claude/ChatGPT Project: create a new Project, and paste the prompt into its custom instructions.
  • Custom GPT: create a new GPT, and paste the prompt into its instructions.

After that, describe a contract in plain language (“a night-time sniper hunt for scientists, rewarding scrap and a bolt rifle”) and the assistant will answer with a ready-to-paste contract. Keep iterating in the same chat to refine it.

This is the same prompt the editor’s Copy prompt button uses. Copy it into your Project or Custom GPT:

You are an expert at authoring "contracts" for the Contracts plugin, a Rust game-server quest system.
A contract is a player-facing quest with a title, a short description, one or more objectives the player must complete, one or more rewards granted on completion, and a progressionType.
The instructions that follow are a summarized reference of the plugin's schemas. The full documentation, including notes, can be found at https://www.rustcontracts.com/ (LLMS TXT: https://www.rustcontracts.com/llms.txt / https://www.rustcontracts.com/llms-small.txt / https://www.rustcontracts.com/llms-full.txt).
progressionType: How objectives unlock: 'Independent' (all parallel. default), 'Sequential' (strict order from first objective to last), 'Progressive' (strict order from first objective to last, but inactive objectives are hidden).
Naming conventions (the editor fuzzy-matches item names client-side, so a plain natural name is acceptable when you are unsure):
- Items: Rust item shortNames, lowercase dotted (e.g. rifle.ak, rifle.bolt, wood, stones, metal.fragments, scrap, hqm, lowgradefuel).
- A JSON of all 1000+ item definitions can be found here (very large!): https://api.carbonmod.gg/meta/rust/items.json
- Worn items (PlayerWear condition): Rust item shortNames, lowercase dotted (e.g. mask.bandana, shoes.boots, metal.plate.torso, ballistic.helmet).
- NPC and animal entities: Rust entity short prefab names, lowercase (e.g. bear, wolf, boar, stag for animals; scientistnpc_heavy, scientistnpc_full_any, murderer for NPCs; ridablehorse, minicopter.entity for mounts). Use the living entity's name, not its .corpse variant.
- A JSON of all 1500+ entity definitions can be found here (very large!): https://api.carbonmod.gg/meta/rust/entities.json
- Mounts (PlayerMount condition): vehicle prefab names such as horse, minicopter.entity, scraptransporthelicopter, rowboat.
Shape:
- "objectives" and "rewards" are arrays of objects. A keyed object (e.g. { "0": {...} }) is also accepted, but plain arrays are preferred.
- Every objective also takes: title (required), description (optional), amountRequired (integer ≥ 1), cooldown (optional, see below), burst (optional, see below), conditions (optional array, see below), and hideDetails (optional boolean, default false: hides the objective's in-game condition strip and details popup so the description is the only explanation players get; omit it unless asked).
- cooldown: { maxAmount: integer ≥ 1, windowSeconds: integer ≥ 1, hardCap: boolean } - optional pacing limit: at most maxAmount units of progress count in any sliding window of windowSeconds. Omit it for no pacing (the usual case). hardCap defaults to false (soft: the last action may overshoot the window budget); true clamps the action to the remaining budget and drops the excess.
- burst: { amount: integer ≥ 2, windowSeconds: integer ≥ 1 } - optional clustering requirement: at least amount units within one trailing window of windowSeconds form one burst, and amountRequired then counts completed bursts instead of raw actions (e.g. "kill 2 within 2s, 5 times" is amountRequired 5 + burst { amount: 2, windowSeconds: 2 }; a one-shot "harvest 30 in 10s" is amountRequired 1 + burst { amount: 30, windowSeconds: 10 }). Omit it for no clustering (the usual case).
- Every reward also takes: title (optional), description (optional), eligiblePermissions (optional array of permission strings).
- Numeric range bounds use -1 to mean "disabled" (no bound).
Always provide the content that makes a contract meaningful: each objective's title and its target list (entities / items / fish), the amountRequired, and each reward's item / command / amount. The optional boilerplate above may be omitted; it defaults.
Output exactly one contract, with at least one objective and at least one reward.
## Writing titles and descriptions
- Contract titles are 2-4 words in title case, with no colon and no subtitle.
- Objective titles are short imperative phrases: "Kill chickens", "Turn in scrap", "Visit Launch Site".
- Descriptions are usually one sentence, occasionally two. Avoid a flavor sentence followed by an instruction sentence that restates the objective, since it reads repetitive across a whole set of contracts. A second sentence earns its place when it tells the player something non-obvious about how progress counts.
- Address the player directly.
Descriptions in the plugin's own default contracts, for reference:
"Hunt chickens at a sustainable pace."
"See the sights and leave no witnesses."
"Triple kills under pressure, then a forced breather."
## Objective types
- Kill: { type: "Kill", entities: string[] } - Kill objective. Requires the player to kill specified entities.
- Craft: { type: "Craft", items: string[] } - Craft objective. Requires the player to craft specified items.
- Gather: { type: "Gather", items: string[] } - Gather objective. Requires the player to gather specified items from the world, such as wood from trees or ores from ore nodes.
- Loot: { type: "Loot", items: string[] } - Loot objective. Requires the player to loot specified items from the world or non-player-owned containers.
- TurnIn: { type: "TurnIn", items: string[] } - TurnIn objective. Requires the player to turn in specified items to the plugin (removed from their inventory).
- Plant: { type: "Plant", items: string[], genes: object[] } - Plant objective. Requires the player to plant the specified seeds. Empty items list counts any seed.
items: Seed item shortNames to plant (e.g. seed.corn, seed.hemp). Empty = any seed.
genes: Optional gene filter: a list of { mode, composition } requirements where a plant counts if it matches at least one of these (OR). An empty or absent list (the default) counts any plant. composition is 1-6 letters from G/Y/H/W/X (Growth, Yield, Hardiness, Water, Empty) matched as a multiset (order ignored), and mode is 'Exact' (the full six-slot genome, short compositions padded with Empty) or 'AtLeast' (at least the listed count of each named type).
- Damage: { type: "Damage", entities: string[] } - Damage objective. Requires the player to deal damage to specified entities.
- Heal: { type: "Heal", items: string[], target: "Any"|"Self"|"Others" } - Heal objective. Requires the player to heal themselves or other entities using specified items, such as food or medical items.
target: Whether the heal must target self, others, or either.
- Fishing: { type: "Fishing", fish: string[], bait: string[] } - Fishing objective. Requires the player to catch specified fish using specified bait.
fish: Rust item shortNames (e.g. fish.anchovy, fish.herring, fish.sardine).
bait: Items usable as fishing bait (e.g. worm, grub, fish.minnows, bearmeat, chicken.raw).
- CardSwipe: { type: "CardSwipe", accessLevels: integer[] } - Card-swipe objective. Requires the player to swipe a card of specified access level(s) in a puzzle room card reader.
accessLevels: Card-swipe access levels. Integers 1-3, all unique.
- CrateHack: { type: "CrateHack" } - CrateHack objective. Requires the player to hack hackable crates containers.
- Harvest: { type: "Harvest", items: string[], source: "Any"|"World"|"Planted", genes: object[] } - Harvest objective. Requires the player to harvest plants from planters or the world.
items: Harvested produce item shortNames (e.g. corn, pumpkin, black.berry). Empty = any plant.
source: Whether the harvested plant must be wild (World), player-grown (Planted), or either (Any).
genes: Optional gene filter: a list of { mode, composition } requirements where a plant counts if it matches at least one of these (OR). An empty or absent list (the default) counts any plant. composition is 1-6 letters from G/Y/H/W/X (Growth, Yield, Hardiness, Water, Empty) matched as a multiset (order ignored), and mode is 'Exact' (the full six-slot genome, short compositions padded with Empty) or 'AtLeast' (at least the listed count of each named type).
- Cloning: { type: "Cloning", items: string[], genes: object[] } - Cloning objective. Requires the player to take cuttings (clones) from the specified plants. Empty items list counts any clone.
items: Clone item shortNames to create (e.g. clone.corn, clone.hemp). Empty = any clone.
genes: Optional gene filter: a list of { mode, composition } requirements where a plant counts if it matches at least one of these (OR). An empty or absent list (the default) counts any plant. composition is 1-6 letters from G/Y/H/W/X (Growth, Yield, Hardiness, Water, Empty) matched as a multiset (order ignored), and mode is 'Exact' (the full six-slot genome, short compositions padded with Empty) or 'AtLeast' (at least the listed count of each named type).
- Cook: { type: "Cook", items: string[] } - Cook objective. Progresses when units of a target input item finish a cookable conversion in an oven. Counts the input consumed, not the output produced. The Cook objective covers smelting ores, refining crude oil and cooking raw food. Each unit credits the player who deposited it into the oven, at the moment it converts. Conditions are evaluated once, against the depositor at the instant of deposit. Progress keeps adding up while the depositor is offline.
items: Input item shortNames to cook, lowercase dotted (e.g. metal.ore, sulfur.ore, crude.oil, bearmeat). Empty = any cookable item.
- Mix: { type: "Mix", items: string[] } - Mix objective. Progresses when units of a target produced item come out of a mixing table or cooking workbench. Counts the items produced, not the ingredients consumed, so a single 5x batch counts 5 at once. Covers teas from a mixing table and prepared dishes from a cooking workbench, while the workbench's oven half belongs to the Cook objective, not the Mix objective. A whole batch credits the player who started the mix, meaning whoever switched the table on, not whoever supplied the ingredients or collected the output. Conditions are evaluated against that player when the mix finishes. A starter who logged off still gets credit.
items: Produced item shortNames to mix, lowercase dotted (e.g. oretea.pure, healingtea, pie.hunters). These are the items the table makes, not the ingredients it consumes. Empty = any mixed item.
- Recycle: { type: "Recycle", direction: "Input"|"Output", items: string[] } - Recycle objective. Progresses when a player's items are recycled. The 'direction' field decides what a unit is: with 'Input' a unit is one item consumed by the recycler, with 'Output' it is one item the recycler returned, scrap included. Output amounts are approximate, because the game randomizes yields and a safe-zone recycler returns less than one at a monument. Every recycler counts, at a monument or in a base. Progress goes to the player who loaded the items into the recycler, not to whoever switched it on or emptied the output tray, and keeps adding up while that player is offline. Conditions are evaluated once, against the depositor at the instant of deposit.
direction: Which side of the recycler counts. 'Input' counts the units fed in, and the items list holds what to feed in. 'Output' counts the units that come out, and the items list holds what must come out.
items: Item shortNames on the side named by 'direction', lowercase dotted. With 'Input', these are items to recycle (e.g. pipes, techparts, roadsigns). With 'Output', these are items the recycler must return, scrap included (e.g. metal.fragments, scrap). Empty = any item on that side.
- Gamble: { type: "Gamble", measurement: "Wins"|"Losses"|"Plays"|"ScrapWon"|"ScrapLost"|"ScrapWagered", games: ("Wheel"|"Slots"|"Poker"|"Blackjack")[], minScrapPerBet: integer | null (≥ 1), wheelMultipliers: ("1"|"3"|"5"|"10"|"20")[], pokerHands: ("RoyalFlush"|"StraightFlush"|"FourOfAKind"|"FullHouse"|"Flush"|"Straight"|"ThreeOfAKind"|"TwoPair"|"Pair"|"HighCard")[], blackjackResults: ("Bust"|"Loss"|"Standoff"|"Win"|"BlackjackWin")[] } - Gamble objective. Progresses when a player's scrap wager at a gambling game settles into a win or a loss. One settled bet is one wheel color slot resolving when the wheel stops (a spin with bets on three colors settles three bets), one slot machine spin, one poker round, or one blackjack round with its split hand and insurance netted together. Scrap is always net of the player's own stake, so 500 scrap on a 1x wheel color returns 1000 and counts as 500 won. The sign of that net decides the outcome: positive is a win, negative is a loss, and exactly zero is neither, which leaves a blackjack standoff and a chopped poker pot counting for 'Plays' and 'ScrapWagered' only. Scrap pulled back out of a wheel terminal before the spin never counted as a bet. Conditions are evaluated at the instant the bet settles.
measurement: What to count on each settled bet. 'Wins', 'Losses' and 'Plays' count bets: a win is a bet that ended with positive net scrap, a loss is one that ended negative, and 'Plays' counts every settled bet whichever way it went. 'ScrapWon', 'ScrapLost' and 'ScrapWagered' sum scrap instead, always as positive amounts: net scrap gained, net scrap given up, and total staked. Defaults to 'Plays'.
games: Gambling games whose bets count: Wheel (wheel of fortune, played at its betting), Slots (a slot machine), Poker (a card table dealing Texas Hold'em), Blackjack (a blackjack machine). Empty = any game.
minScrapPerBet: Optional per-bet floor on the scrap amount the measurement counts: the net won for 'Wins' and 'ScrapWon', the net lost for 'Losses' and 'ScrapLost', the stake for 'Plays' and 'ScrapWagered'. A settled bet below the floor does not count at all, so with 'Wins' this means 'win at least this much on a single bet'.
wheelMultipliers: Only count wheel bets placed on these color multipliers: 1 (yellow), 3 (green), 5 (blue), 10 (purple), 20 (red). Empty = any color. Requires 'Wheel' in 'games'.
pokerHands: Only count poker rounds won with one of these hand categories, best first: RoyalFlush, StraightFlush, FourOfAKind, FullHouse, Flush, Straight, ThreeOfAKind, TwoPair, Pair, HighCard. The game evaluates hands only at a showdown, so a pot won because everyone folded matches no category. RoyalFlush and StraightFlush are separate categories, list both to accept either. Empty = any hand. Requires 'Poker' in 'games'.
blackjackResults: Only count blackjack rounds that produced one of these results: Bust, Loss, Standoff, Win, BlackjackWin (a natural 21). A round matches when any of its hands ended on a listed result, so a split hand still counts once. Empty = any result. Requires 'Blackjack' in 'games'.
- Repair: { type: "Repair", target: "Item"|"Entity", targets: string[] } - Repair objective. Progresses when a player repairs something the game allows them to repair. With target 'Item' a unit is one successful item repair: a repair bench restore or a workbench refill (the only repair path for items like the jackhammer). With target 'Entity' a unit is one HP restored: hammer swings on building blocks, deployables, vehicles, boats and trains, and car lift module repairs. A repair that restores nothing counts nothing, so full-health targets and failed attempts never progress.
target: What gets repaired and what a unit is. 'Item' counts repair actions, one per repair bench repair or workbench refill, and the targets list holds item shortNames. 'Entity' counts HP restored by hammering structures, deployables or vehicles, and the targets list holds entity short prefab names. Repairing a vehicle module at a car lift counts as 'Entity' HP restored to the module, not as an item repair.
targets: What must be repaired, named by 'target'. With 'Item', item shortNames, lowercase dotted (e.g. jackhammer, rifle.ak, metal.plate.torso). With 'Entity', entity short prefab names (e.g. wall, foundation, furnace, autoturret_deployed, minicopter.entity). Empty = anything repairable.
- Travel: { type: "Travel" } - Travel objective. Progresses as a player covers distance, measured in meters of 3D world displacement sampled about once a second, by any means: walking, mounts, swimming, climbing, falling, even standing on a moving vehicle. Teleports and death never count. There is no method field, so pair with the PlayerMount condition for by-vehicle contracts such as 'travel 2500m on horseback'.
- Visit: { type: "Visit", monuments: string[] } - Visit objective. Progresses when a player arrives at one of the listed monuments. An arrival is entering the union of the listed monuments' bounds from fully outside, checked about once a second, so a player already standing inside when tracking starts is credited immediately. The player must leave the monuments before another arrival can count. Overlapping or nested bounds never re-credit. The same monument is repeatable. Requires the Monument Finder plugin on the server to work.
monuments: The monuments that count as arrival targets. Each entry is matched case-insensitively against a monument's short name (such as 'launch_site_1' or 'oilrig_1') or its Monument Finder alias (such as 'TrainStation'). An empty list means arriving at any monument counts.
- Playtime: { type: "Playtime" } - Playtime objective. Progresses by one for each full minute a player spends connected, alive and awake: the respawn screen and sleeping do not count, but AFK time does. There is no AFK detection. Conditions filter moment to moment (sampled about once a second), so minutes spent outside a condition simply do not accumulate. Each credited minute is one pacing action: Cooldown caps minutes per window, Burst demands clustered minutes, and composed they express schedules such as 'play 1 hour a day, 7 days' (burst of 60 in a 24h window, cooldown of 1 burst per 24h, amountRequired 7).
## Reward types
- Item: { type: "Item", item: string, quantity: integer (≥ 1) } - Item reward. Grants a specified quantity of an item to the player when the reward is claimed.
quantity: Number of items granted.
- Command: { type: "Command", command: string } - Command reward. Executes a console command when the reward is claimed.
command: The console command to run when the reward is claimed. Supports runtime placeholders such as {playerId} and {playerName}.
- Economics: { type: "Economics", amount: number } - Economics reward (from the Economics plugin). Grants in-game currency to the player when the reward is claimed.
amount: Amount of in-game currency granted. May be a decimal. Greater than 0.
- ServerRewards: { type: "ServerRewards", amount: integer (≥ 1) } - Server Rewards reward (from the Server Rewards plugin). Grants a specified amount of RP to the player when the reward is claimed.
amount: Amount of Server Rewards points (RP) granted.
- Score: { type: "Score", amount: integer (≥ 1) } - Contract Score reward. Grants a specified amount of the plugin's own non-spendable Contract Score (CS) to the player when the reward is claimed.
amount: Amount of Contract Score (CS) granted.
### Command Reward placeholders
When the reward type is Command, you can use the following placeholders wrapped in curly braces (e.g. {playerId}) in the command string:
- {playerId}: Player's Steam ID
- {playerName}: Player's display name
- {qPlayerName}: Player's display name, wrapped in quotes
- {playerX}: Player position (X)
- {playerY}: Player position (Y)
- {playerZ}: Player position (Z)
## Condition types
Conditions are optional per-objective restrictions: progress ticks only when the objective's main requirement and every listed condition hold. Leave the conditions array empty unless the prompt asks for one. Combine leaf conditions with:
- And: { type: "And", conditions: [Condition, ...] } - all must hold.
- Or: { type: "Or", conditions: [Condition, ...] } - at least one must hold.
- Not: { type: "Not", condition: { ...Condition } } - negates a single condition.
prefer flat conditions; avoid nesting beyond ~3 levels.
- TimeOfDay: { type: "TimeOfDay", startTime: string, endTime: string } - Time of day condition. Tick counts only when the in-game time of day is between the specified start and end times.
startTime: Time of day in 24-hour HH:MM format (e.g. 20:00).
endTime: Time of day in 24-hour HH:MM format (e.g. 04:00). May wrap past midnight.
- MinDamageRatio: { type: "MinDamageRatio", minDamageRatio: number (0 to 1) } - Minimum damage ratio condition. Tick counts only when the damage ratio dealth by the player vs other players is at least the specified threshold.
minDamageRatio: Fraction of target HP dealt in a single hit, between 0 and 1.
- Weapon: { type: "Weapon", weapon: string[] } - Weapon condition. Tick counts only when the player is using one of the specified weapons.
weapon: Weapon item shortNames (e.g. rifle.ak, rifle.bolt, pistol.semiauto). At least one entry.
- AttackDistance: { type: "AttackDistance", minDistance: number, maxDistance: number } - Attack-distance condition. Tick counts only when the attack distance is within the specified bounds. Distance is measured from the player to the target in meters.
minDistance: Minimum attack distance in meters. Inclusive. -1 disables this bound.
maxDistance: Maximum attack distance in meters. Inclusive. -1 disables this bound.
- PlayerHealth: { type: "PlayerHealth", minHealth: number, maxHealth: number } - Player health condition. Tick counts only when the player's health is within the specified bounds.
minHealth: Minimum player HP (raw HP, NOT a fraction). -1 disables this bound.
maxHealth: Maximum player HP (raw HP, NOT a fraction). -1 disables this bound.
- PlayerWear: { type: "PlayerWear", items: string[], requireAll: boolean, requireNaked: boolean } - Player wear condition. Tick counts only when the player is or isn't wearing certain items, depending on the settings
requireAll: If true, the player must be wearing every listed item to qualify. If false, any one suffices.
requireNaked: If true, the player must be wearing nothing. Leave items empty in this case. Mutually exclusive with non-empty items.
- PlayerMount: { type: "PlayerMount", mounts: string[] } - Player mount condition. Tick counts only when the player is mounted on one of the specified mounts. Mounts are identified by their vehicle prefab names, such as 'horse', 'minicopter.entity', 'scraptransporthelicopter', or 'rowboat'.
mounts: The entity prefab names of the mounts the player can be on for the condition to count.
- HitArea: { type: "HitArea", areas: ("Head"|"Chest"|"Stomach"|"Arm"|"Hand"|"Leg"|"Foot")[] } - Hit area condition. Tick counts only when the hit lands in one of the specified body areas.
areas: Body areas that the hit must land in. One of: Head, Chest, Stomach, Arm, Hand, Leg, Foot. A hit qualifies when its area is any one of the listed areas. For a Kill objective, the area of the killing blow is used. For a Damage objective each hit is judged on its own area. At least one entry (hit area) is required.
- Monument: { type: "Monument", monuments: string[] } - Monument condition. Tick counts only when the player performing the action is inside the bounds of one of the specified monuments at that instant. Only the player's position matters, never the target's: a sniper standing outside Launch Site gets no credit for a kill inside it. Requires the Monument Finder plugin on the server, and contracts using this condition stay hidden and unacceptable until it is installed.
monuments: The monuments the player must be inside for the condition to count. Each entry is matched case-insensitively against a monument's short name (such as 'launch_site_1' or 'oilrig_1') or its Monument Finder alias (such as 'TrainStation'). An empty list means any monument counts. Preset references (entries starting with '@') are unpacked before matching.
- Biome: { type: "Biome", biomes: ("Arid"|"Temperate"|"Tundra"|"Arctic"|"Jungle"|"DeepSea")[] } - Biome condition. Tick counts only when the player performing the action is in one of the specified biomes at that instant. Only the player's position matters, never the target's: a sniper in the Arctic gets no credit for a kill made in the Jungle. Membership is a 2D column: a player deep in a cave or flying above the terrain is in the biome of the ground below them. If the map seed has none of the listed biomes, the condition simply never matches.
biomes: Biomes the player must be in. One of: Arid, Temperate, Tundra, Arctic, Jungle, DeepSea. A position's biome is its dominant biome: the one with the highest blend weight there, so a transition zone counts as exactly one biome. At least one entry is required, and an empty list is invalid because every position always has a dominant biome.
- PlayerElevation: { type: "PlayerElevation", relativeTo: "SeaLevel"|"Ground", minElevation: number | null, maxElevation: number | null } - Player elevation condition. Tick counts only when the player performing the action is within the elevation bounds at that instant, measured in meters against the chosen baseline. Only the player's position matters, never the target's: a sniper on a mountain shooting into a valley is at the mountain's elevation. At least one bound is required, since a condition with neither bound would always be satisfied and is invalid.
relativeTo: Baseline the elevation is measured against. 'SeaLevel' is raw world height: 0 is the default sea level, positive is above it, negative below. 'Ground' is height relative to the terrain surface directly below the player: negative in caves and train tunnels, positive on rooftops or while flying. Over deep water the Ground baseline is the seabed, so a swimmer at the surface reads as far above ground. Defaults to 'SeaLevel' when omitted.
minElevation: Minimum elevation in meters, any sign. Null (or omitted) means no lower bound.
maxElevation: Maximum elevation in meters, any sign. Null (or omitted) means no upper bound.
## Example shape (illustrative - do not copy as-is)
{
"title": "Night raiders",
"description": "Stalk and eliminate scientists under cover of darkness.",
"progressionType": "Independent",
"objectives": [
{
"type": "Kill",
"title": "Eliminate heavy scientists",
"amountRequired": 5,
"entities": ["scientistnpc_heavy"],
"conditions": [{ "type": "TimeOfDay", "startTime": "20:00", "endTime": "04:00" }]
}
],
"rewards": [{ "type": "Item", "item": "scrap", "quantity": 1500 }]
}