Skip to main content

Creating Submissions

createOrderSubmission submits one order; bulkCreateOrderSubmissions submits many in a single call with per-item error reporting. Both take the same per-order input.

CreateOrderSubmissionInput

Targeting

An order trades exactly one asset configuration, and that configuration is the only thing that names the instrument. Name it with assetConfigurationIds (a list of one) or with externalIdentifiers that resolve to one. marketIds is venue scope — which books the order may rest in — not a way to target products, and assetIds is rejected outright. A list of two configurations, or assetIds, fails validation before anything persists (VALIDATION_ERROR).

FieldTypeDescription
assetConfigurationIds[UUID!]Exactly one configuration
externalIdentifiersJSONYour platform's product IDs, resolved to that one configuration for you — see below
keyIds[UUID!]Graded/condition keys within the configuration. A SELL names exactly one — the key its units carry. A BUY may name several, OR'd. Immediate orders (MARKET, IOC, FOK) must name at least one
keyScopeJSONKey vocabulary by KeyType, resolved to keyIds for you — see below
marketIds[UUID!]Venues the order may rest in. Omit to rest on the unvaulted marketplace books; a vaulted market must be named. Venues you can't trade in are dropped — resolvedMarketIds on the response says what actually rested
assetIds[UUID!]Rejected — not a targeting field

Targeting by external identifiers

externalIdentifiers maps platform → id (or list of ids). Every id must resolve to the same asset configuration — a quote and an order price one instrument. Pass it via variables — inline literals reject quoted keys:

{ "externalIdentifiers": { "TCGPLAYER": "123" } }

Resolution is all-or-nothing; on failure nothing persists. The identifiers you sent are echoed back on reads. If you also pass assetConfigurationIds, the resolved configuration must be that one.

Error codeMeaning
UNSUPPORTED_PLATFORMUnrecognized platform key
UNRESOLVED_EXTERNAL_IDENTIFIERSIds with no mapping — the message names them
SINGLE_CONFIGURATION_REQUIREDThe ids resolved to more than one configuration, or to a second one beside an explicit assetConfigurationIds

Supported platform keys are listed per asset class in each vertical's External IDs table — see Verticals.

Targeting by key scope

keyScope maps a KeyType to human values and compiles to keyIds against the targeted configuration's keys. Hierarchical types compose: a row narrows its section, a grade narrows its grading company. Mutually exclusive with keyIds; requires assetConfigurationIds or externalIdentifiers targeting (KEY_SCOPE_REQUIRES_CONFIG_TARGETING). Pass via variables:

{ "keyScope": { "SEATMAP_SECTION": ["416"], "SEATMAP_ROW": ["F"] } }

All-or-nothing; nothing persists on failure. Each vertical's key types are listed under Catalog keys.

Error codeMeaning
UNSUPPORTED_KEY_TYPEUnrecognized key type
UNRESOLVED_KEY_SCOPEValues with no matching key — the message names them
KEY_SCOPE_UNMATCHED_CONFIGThe combination matches no keys for a targeted configuration
MUTUALLY_EXCLUSIVE_KEY_TARGETINGBoth keyScope and keyIds were passed

Order shape

FieldTypeDescription
directionOrderSubmissionDirection!BUY or SELL
orderTypeOrderSubmissionType!LIMIT or MARKET
timeInForceOrderSubmissionTimeInForceGTC (default), DAY, IOC, FOK. A DAY order expires at the next regular session close; don't set expiresAt on one
qtyInt!Units to trade. Greater than zero (INVALID_QTY)
allInPriceIntFee-inclusive limit per unit, in cents. Required for LIMIT (MISSING_PRICE)
allOrNoneBooleanDefault false. Sugar for minOrderSize == qty
slippage[SlippageConfigInput!]Slippage tolerance for market orders — see SlippageConfig for the entry rules
expiresAtDateTimeOptional hard expiry
externalReferenceIdStringYour identifier — echoed back on reads, usable for lookup and bulk cancel. Unique per account: a reuse is refused with DUPLICATE_EXTERNAL_REFERENCE, which makes it your idempotency key

Buy-side fulfilment intents

These describe what happens to something bought, so omit them on a SELL — leaving them unset is meaningful and is not the same as passing false.

FieldTypeDescription
paymentRailPaymentRailHow fills are paid for
paymentTokenIdUUIDPayment token charged on fills
autoOuttakeBooleanShip filled units automatically after settlement
shouldVaultBooleanRoute what this order buys to a vault instead of your own address. The destination vault resolves from your facility configuration for the traded asset scope — mutually exclusive with recipientAddressId
recipientAddressIdUUIDWhere filled units ship
maxShippingAndHandlingCostsCents[Int!]Taker-pays shipping acknowledgment — see Taker-pays shipping
serviceLevelIdUUIDRest a priority bid under this service level — see Priority bids

Sell-side fields

FieldTypeDescription
originAddressIdUUIDWhere inventory ships from
minOrderSizeIntSmallest fill accepted
minValueCentsIntMinimum value per fill, in cents
fulfillFromVaultBooleanFill this sell from your vaulted stock — the facility ships to the buyer instead of you. Immediate (taker) sells on marketplace books only; a resting ask is backed by units you hold
autoAddUnvaultedInventoryBooleanUnvaulted marketplace sells: if you're short of qty, create the missing units (stock you declare you hold) instead of requiring an inventory add first. Ignored on a vaulted sell
expectingFreeShippingBooleanYou saw free shipping on the quote. The execution re-checks and rejects if it no longer holds
priorityBidIdUUIDTake exactly this priority bid — see Taking a priority bid

Taker-pays shipping

A BUY that takes seller-shipped (unvaulted) asks pays the shipping, and a fill never charges shipping you didn't acknowledge. Quote first with enqueueShippingQuote: true and a destination; the quote returns shipping.expectedShipments. Pass their estimatedCostCents as maxShippingAndHandlingCostsCents — one ceiling per shipment — along with the quote's shipping.recipientAddressId.

A fill that would ship to you without an acknowledgment rejects with SHIPPING_ACK_REQUIRED; a bid that only rests needs none. Pass [] to accept free shipments only.

Priority bids

A priority bid is a BUY resting under a service level — a ship-by commitment the seller who takes it agrees to, priced by the level's fee modifier. Pass a serviceLevelId from listOrderServiceLevels on a GTC LIMIT buy naming one unvaulted market. Its expiry is computed from the level, so leave expiresAt unset. Priority bids are immutable: cancel and recreate to change one.

Taking a priority bid

Sellers see priority bids they can take under getOrderQuote.featuredOrders. To take one, submit an immediate SELL (MARKET, or LIMIT with IOC/FOK) with priorityBidId and restate assetConfigurationIds, keyIds, marketIds, and serviceLevelId as the featured order shows them. It needs originAddressId — you ship it yourself by the level's deadline, with free shipping. If the bid was taken or changed before your sell locked it, the order cancels with PRIORITY_BID_UNAVAILABLE. A take is a single order; use createOrderSubmission, not bulk.

Creating one order

mutation {
createOrderSubmission(input: {
assetConfigurationIds: ["315bc6db-3f16-49ec-b649-8be3b8753fb7"]
keyIds: ["4a9a2cca-c05f-5474-9979-428dc6f41107"]
direction: BUY
orderType: LIMIT
timeInForce: GTC
qty: 1
allInPrice: 500
externalReferenceId: "docs-demo-single"
}) {
submission { id status direction orderType timeInForce qty allInPrice externalReferenceId createdAt }
orderExecutions { id }
error { message }
}
}
{
"createOrderSubmission": {
"submission": {
"id": "77a083a9-ad84-4191-837b-630f3da9ea86",
"status": "QUEUED",
"direction": "BUY",
"orderType": "LIMIT",
"timeInForce": "GTC",
"qty": 1,
"allInPrice": 500,
"externalReferenceId": "docs-demo-single",
"createdAt": "2026-08-11T19:11:38.194645Z"
},
"orderExecutions": [],
"error": null
}
}

Two things to notice:

The submission returns QUEUED. Resting on the book happens asynchronously — moments later a read shows it live:

query {
getOrderSubmission(input: { externalReferenceId: "docs-demo-single" }) {
submission { id status }
filledQuantity
remainingQuantity
settledQuantity
}
}
{
"submission": { "id": "77a083a9-ad84-4191-837b-630f3da9ea86", "status": "RESTING" },
"filledQuantity": 0,
"remainingQuantity": 1,
"settledQuantity": 0
}

resolvedMarketIds is what actually rests. marketIds is what you asked for; a venue you can't trade in is dropped rather than erroring, so the two can differ. Read resolvedMarketIds if you need to know where the order sits.

Crosses are not in the create response. Because matching is asynchronous, orderExecutions on the payload is empty in practice, even for an order that crosses immediately. A taker learns what it traded from a follow-up read, from listOrderExecutions filtered by orderSubmissionId, or from the order lifecycle stream. An IOC that finds nothing goes QUEUEDCANCELLED with remainingQuantity equal to qty; a FOK that cannot fill in full does the same.

Creating in bulk

bulkCreateOrderSubmissions wraps a list of the same input. Items succeed or fail independently: valid items are created, invalid ones come back in errors keyed by list index and your externalReferenceId. A bulk call with some bad items is not an error — check errors, not just error.

mutation {
bulkCreateOrderSubmissions(input: {
submissions: [
{ assetConfigurationIds: ["315bc6db-3f16-49ec-b649-8be3b8753fb7"], keyIds: ["4a9a2cca-c05f-5474-9979-428dc6f41107"], direction: BUY, orderType: LIMIT, qty: 2, allInPrice: 450, externalReferenceId: "docs-demo-bulk-1" },
{ assetConfigurationIds: ["315bc6db-3f16-49ec-b649-8be3b8753fb7"], keyIds: ["4a9a2cca-c05f-5474-9979-428dc6f41107"], direction: BUY, orderType: LIMIT, qty: 1, externalReferenceId: "docs-demo-bulk-2" }
]
}) {
submissions { id externalReferenceId status qty allInPrice }
errors { index externalReferenceId message code }
orderExecutions { id }
error { message }
}
}

The second item is a LIMIT with no allInPrice:

{
"bulkCreateOrderSubmissions": {
"submissions": [
{
"id": "dbebb414-9818-4f34-80d3-80ae11403966",
"externalReferenceId": "docs-demo-bulk-1",
"status": "QUEUED",
"qty": 2,
"allInPrice": 450
}
],
"errors": [
{
"index": 1,
"externalReferenceId": "docs-demo-bulk-2",
"message": "all_in_price required for LIMIT orders",
"code": "MISSING_PRICE"
}
],
"orderExecutions": [],
"error": null
}
}

BulkSubmissionError

FieldTypeDescription
indexInt!Position of the failed item in your submissions list
externalReferenceIdStringEcho of that item's reference id, when it had one
messageString!Human-readable reason
codeString!Stable machine code, e.g. MISSING_PRICE

An empty submissions list returns EMPTY_INPUT.

Refusals

Beyond the targeting and shape codes above, a create can be refused for who you are and what you hold. All arrive as the payload's error { code } with nothing persisted.

CodeMeaning
KYC_REQUIREDThe venue requires identity verification for this trade
PAYOUT_METHOD_REQUIREDThe venue requires a payout method on file
PRICE_REQUIREDThe venue gates by order size; a bare MARKET order cannot be sized — pass allInPrice
ACCESS_DENIEDNo venue in scope admits this account for this side
BUYER_CONFIGURATION_NOT_FOUNDA marketplace (unvaulted) buy needs a buyer configuration on the account for this asset class
INSUFFICIENT_BALANCEYour Tradepost balance does not cover the buy
INSUFFICIENT_VAULTED_QUANTITYA vaulted sell exceeds the units you hold in the facility
VAULT_ADDRESS_CONFLICTBoth shouldVault and recipientAddressId were set
INVALID_ADDRESSrecipientAddressId / originAddressId is not one of your saved addresses
UNSUPPORTED_ORDER_MODEThe direction × type × time-in-force combination is not enabled — see below

Supported combinations

Not every direction × order type × time in force is guaranteed to be enabled. Query orderCapabilities for the live set:

query {
orderCapabilities {
supportedCombinations { direction orderType timeInForce }
}
}