Bids
Place bids on inventory programmatically and read your team's bids. Placing a bid requires the bids.write scope and a token bound to a team via Login with MGX. Reading uses bids.read. Responding to a bid — accept, reject, counter — needs only bids.write, and works for sellers, who have no team.
The counterparty (seller) on a bid stays null until both invoices on the resulting trade are paid.
Place a bid
Place a bid on a listing. MGX runs the same credit, payment, and eligibility rules as the web app. Pass an Idempotency-Key header to make retries safe.
Body
- Name
price- Type
- object
- Description
- amount in MT — for graded listings.
- Name
bids- Type
- array
- Description
- [ grade, price ] — for ungraded (multi-grade) listings.
- Name
quantity_mt- Type
- number
- Description
- Quantity in tonnes (required).
- Name
delivery- Type
- object
- Description
- from, to ISO dates (required).
- Name
fob_farm- Type
- boolean
- Description
- Defaults true.
- Name
delivery_location_id- Type
- integer
- Description
- Required when not FOB.
- Name
subject_to_sample_approval- Type
- boolean
- Description
- Name
additional_terms- Type
- string
- Description
- Free text (moderated).
- Name
expires_at- Type
- string
- Description
- ISO datetime; defaults to +7 days.
Request
curl https://api.mygrainexchange.com/v1/inventory/inv_3Kd9aZ/bids \
-H "Authorization: Bearer {token}" \
-H "Idempotency-Key: 7f1c..." \
-H "Content-Type: application/json" \
-d '{
"price": { "amount": 308.00, "unit": "MT" },
"quantity_mt": 86.0,
"delivery": { "from": "2026-08-15", "to": "2026-09-15" },
"fob_farm": true
}'
Response
{
"data": {
"id": "bid_7Qp2",
"reference": "BID-10482",
"inventory_id": "inv_3Kd9aZ",
"status": "pending",
"price": { "amount": 308.0, "currency": "CAD", "unit": "MT" },
"quantity_mt": 86.0,
"counterparty": null
}
}
List your bids
Bids placed by your team. Filter with status (pending, accepted, rejected, countered, expired). Poll this to discover lifecycle changes (e.g. a lot delisting).
Request
curl https://api.mygrainexchange.com/v1/bids?status=pending \
-H "Authorization: Bearer {token}"
Get a bid
Retrieve one of your team's bids by id. Returns 404 if it does not belong to your team.
Request
curl https://api.mygrainexchange.com/v1/bids/bid_7Qp2 \
-H "Authorization: Bearer {token}"
Respond to a bid or counter-offer
These three endpoints are used by both sides of a deal:
- As a buyer, when a seller counters your bid (the
bid.counteredwebhook). - As a seller, when a buyer bids on your listing (the
bid.receivedwebhook). Sellers have no team, and these endpoints do not require one — read your received bids fromGET /v1/me/inventory/:id/bidsand pass the bid id straight through. The team-scopedGET /v1/bids/:idis buyer-only and will return400 no_teamfor a seller token; you do not need it.
All three need the bids.write scope. They return 404 if you are not a party to the bid, and 422 if it is no longer pending.
Accept
Accept the bid. This creates the trade and both invoices.
A bid on a graded listing carries one price and needs no body. A bid on an ungraded listing prices each grade separately and comes back with a grades[] array — accepting one requires bid_items naming the lines you are taking, and every other line on the bid is rejected. Each entry may be a grade name or a line id, bare or wrapped: ["No. 2 or Better"], [{ "grade": "No. 2 or Better" }], or [{ "id": "86" }].
Omitting bid_items on a multi-grade bid returns 422 bid_items_required, listing the grades available on that bid.
Request
# Graded listing — single price, no body needed
curl -X POST https://api.mygrainexchange.com/v1/bids/bid_7Qp2/accept \
-H "Authorization: Bearer {token}"
# Ungraded listing — name the grade lines you are taking
curl -X POST https://api.mygrainexchange.com/v1/bids/bid_7Qp2/accept \
-H "Authorization: Bearer {token}" \
-H "Content-Type: application/json" \
-d '{ "bid_items": ["No. 2 or Better"] }'
Reject
Decline the bid outright. No body.
Request
curl -X POST https://api.mygrainexchange.com/v1/bids/bid_7Qp2/reject \
-H "Authorization: Bearer {token}"
Counter back
Send your own counter back to the other party. Same body shape as placing a bid (price, quantity, delivery). As a seller, this is how you counter a buyer's bid on your listing.
Request
curl -X POST https://api.mygrainexchange.com/v1/bids/bid_7Qp2/counter \
-H "Authorization: Bearer {token}" \
-H "Content-Type: application/json" \
-d '{ "price": { "amount": 305.0, "unit": "MT" }, "quantity_mt": 86.0, "delivery": { "from": "2026-08-15", "to": "2026-09-15" }, "expires_at": "2026-06-25T17:00:00Z" }'
List your delivery locations
Elevators bidding for delivered grain (not FOB farm) must name one of their own delivery locations. List them here, then pass the integer id as delivery_location_id when placing the bid. FOB-farm bids need no location.
Request
curl https://api.mygrainexchange.com/v1/delivery-locations \
-H "Authorization: Bearer {token}"