PearPear
API IntegrationImportant Terms

Orders and Executions

What a trigger, schedule, ladder, execution, order, and fill each are, and how one becomes the next.

Pear splits one trade into several objects, and their names overlap enough to be confusing. This page defines each one and shows how they connect. Read it once and the rest of the API section reads straightforwardly.

"Order" means two different things

This is the first thing to get straight, because both meanings appear in the same response.

  • An instruction you place — a trigger, a TWAP schedule, or a ladder. It waits for something, then acts. The Managing Open Order and Open Order pages mean this one.
  • A venue order Pear sends — one entry in an execution's orders array, one per leg, holding the exchange's own status. It has no endpoint of its own.

When a page says "resting order" or "open order", it means the first. When you see orders inside a response body, it is the second.

The objects

ObjectWhat it isRead with
TriggerAn instruction that fires when a market condition is met.GET /triggers
ScheduleAn instruction that fires on a clock, slice by slice. TWAP.GET /schedules
LadderA group of triggers spread across a price range.GET /ladders
ExecutionOne run at the venue. Holds the venue orders it sent.GET /executions
OrderOne venue order inside an execution, one per leg.inside execution.orders
FillOne print the venue reports, with its price and fees.GET /fills
PositionThe basket you hold, once fills net out.GET /positions

How one becomes the next

A market order has no instruction step: POST /trade/open creates an execution straight away, so there is nothing on GET /triggers to find.

How many executions each produces

This is the part that surprises people.

You placedExecutions it produces
A market orderExactly one.
A triggerOne, when it fires. The trigger is then spent and reports TRIGGERED.
A scheduleOne per slice. A TWAP over twelve slices produces twelve.
A ladderOne per rung that fires, up to levels.

Because a schedule and a ladder produce many, GET /executions hides their runs by default, so one TWAP does not bury every other action. Add includeSchedule=true or includeTriggers=true to see them. See Execution.

A ladder is made of triggers

A ladder is a parent with one child trigger per rung, spaced evenly across your range and each carrying an equal share of the size. levels sets the rung count, from 2 to 50, and weighting is always EQUAL.

That has three consequences:

  • A ladder has no executions of its own. A rung's execution names the trigger, and that trigger carries ladderId and ladderIndex.
  • Ladder rungs show up on GET /triggers alongside your other triggers. Filter them out by ladderId when you do not want them.
  • GET /ladders returns each ladder with its rungs attached, ordered by ladderIndex, which is the easier way to read a ladder's progress.

An instruction outlives the wait

Firing does not delete the instruction. A trigger that fired is still readable, now reporting TRIGGERED, with the fills it produced attached. The list endpoints return every state by default, so ask for status=ACTIVE when you want only what is still resting. See Open Order.

Filtering a list by status

status accepts exactly three values, on every list that takes it: ACTIVE, COMPLETED, CANCELLED. They are a query vocabulary, not the object's own statuses, and they do not line up one to one.

ListTakes statusWhat COMPLETED selects
GET /triggersYesTriggers reporting TRIGGERED.
GET /executionsYesExecutions reporting COMPLETED or FAILED.
GET /schedulesYesSchedules reporting COMPLETED or FAILED.
GET /laddersNo

Three consequences:

  • GET /ladders has no status filter. Sending status=ACTIVE there is silently dropped and you get every ladder, in every state. Filter client-side.
  • status=COMPLETED includes failures on executions and on schedules. Read each row's own status before you treat it as a success.
  • FAILED is not selectable. There is no status=FAILED. Ask for COMPLETED and filter the response.

Statuses at a glance

Each object has its own vocabulary. None of them share a set, so do not reuse a status check across two.

ObjectStatuses
TriggerACTIVE, TRIGGERED, CANCELLED
ScheduleACTIVE, COMPLETED, FAILED, CANCELLED
LadderACTIVE, COMPLETED, CANCELLED
ExecutionIDLE, ACTIVE, COMPLETED, FAILED, CANCELLED
OrderPENDING, PARTIAL, FILLED, CANCELLED, REJECTED
FillPROVISIONAL, CONFIRMED, RECONCILED
PositionOPEN, CLOSED

intent is a separate vocabulary again, and the three objects that carry it do not share a set either:

Objectintent values
TriggerOPEN, ADJUST, CLOSE
ScheduleOPEN, CLOSE
ExecutionOPEN, ADJUST, CLOSE, REVERSE

One trap lives in here: an execution can be FAILED while some of its orders are FILLED, which is how a basket ends up one-sided. See Error Handling.

Cancelling

Cancelling removes what has not happened yet. It never unwinds what has.

CancelStopsLeaves
A triggerThe trigger firing.Nothing; it never ran.
A scheduleIts pending slices.Every slice that already filled, as part of your position.
A ladderIts unfired rungs.Every rung that already filled.

So cancelling a half-finished TWAP leaves you holding whatever it built. Read that with GET /positions. See Managing Open Order.

You are not the only thing that cancels. A cancelled trigger or schedule carries a cancelledReason, and only one of its values is you:

cancelledReasonWhat happened
USERYou cancelled it.
POSITION_CLOSEDThe position it was attached to closed.
POSITION_NETTEDThe position was netted away against an opposing one.
POSITION_REVERSEDThe position was reversed, so the bracket no longer matches the exposure.
SYSTEMPear cancelled it.

A close trigger you never touched can therefore turn up CANCELLED. Check the reason before you treat it as user action.

cancelledReason is absent unless the object was cancelled. Schedules carry the same five values.

States before the object is armed

Two objects have an internal state that precedes ACTIVE, and they surface it differently:

  • A trigger is created IDLE, then armed. GET /triggers filters IDLE out unconditionally, whatever status you pass, so you never see one.
  • An execution is created IDLE, before its orders exist. It can come back on GET /executions, but there is no status=IDLE to ask for it. Treat it as "not started yet".
  • A position is OPENING while an order is still trying to create exposure. That state never reaches the API. On the wire a position is only ever OPEN or CLOSED.

Close triggers are triggers too

A take profit or a stop loss is a trigger with intent: "CLOSE". It appears on GET /triggers next to your entry triggers, and produces a closing execution when it fires. Tell them apart with intent.

Two fields need care:

  • The position it closes is at context.position.id, not at a top-level positionId. There is no top-level positionId on any trigger. An adjust trigger nests it the same way.
  • Read semanticBracketType, not bracketType, for which side it protects. bracketType is the crossing encoding the gateway fires on, and it is flipped on a price bracket that watches a short leg, so it does not report what the user asked for. semanticBracketType does. It is absent only where an older client's encoding cannot be recovered; in that case report nothing rather than presenting bracketType as intent.

See Take Profit / Stop Loss.

Not on this list: auto-rebalance

Auto-rebalance is a standing config rather than an instruction that fires once. It is ACTIVE or PAUSED, read with GET /rebalance/auto, and its history is at GET /rebalance/{positionId}/events rather than in the execution list. See Auto-Rebalance.

Where each is documented

ToGo to
Place oneOrder Type
Cancel oneManaging Open Order
Read resting instructionsOpen Order
Read what ranExecution
Read the printsFills
Read what you holdOpen Position

On this page