Documentation Index
Fetch the complete documentation index at: https://docs.tryhoard.com/llms.txt
Use this file to discover all available pages before exploring further.
Upload orders
Upload parsed order data from TCGplayer’s order export. The request is shape-validated
synchronously and queued for upsert in a background job — the response is 202 Accepted
and the database write happens asynchronously. Orders are upserted by
(user_id, order_number) so re-uploading the same orders is safe.
POST /api/v1/orders
Content-Type: application/json
The endpoint accepts both raw JSON and gzip-compressed JSON. For large batches
(typically the first full-history upload), gzip is preferred — set
Content-Type: application/gzip and gzip the JSON body. The server transparently
decompresses gzip and falls back to raw bytes when the body is not gzip-encoded.
Request body:
[
{
"order_number": "ORD-12345",
"buyer_name": "John Doe",
"order_date": "3/27/2026",
"status": "Completed",
"product_amt": 24.99,
"shipping_amt": 0.99,
"total_amt": 25.98
}
]
Order object fields
| Field | Type | Required | Description |
|---|
order_number | string | Yes | TCGplayer order number. Used as the unique key for upserts. |
buyer_name | string | No | Buyer’s display name from the order. |
order_date | string | No | Order date as parsed from TCGplayer CSV (e.g., "3/27/2026"). |
status | string | No | Order status from TCGplayer (e.g., "Completed", "Cancelled"). |
product_amt | number | No | Product subtotal in USD. |
shipping_amt | number | No | Shipping amount in USD. |
total_amt | number | No | Total order amount in USD. |
Response:
{"status": "accepted", "count": 1}
HTTP status is 202 Accepted — the server has validated the payload shape and
enqueued the upsert. The count field reflects the number of orders in the
request (not the number of new rows — duplicates are updated in place).
If an active Pull session exists, the same upload also checks refreshed orders
against Pull eligibility. Orders that are now cancelled, shipped, refunded, or
otherwise no longer pullable stay in the session but are marked for review so
the tablet queue can warn the puller instead of silently dropping work.
curl example
curl -X POST \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '[{"order_number":"ORD-12345","buyer_name":"John Doe","order_date":"3/27/2026","status":"Completed","product_amt":24.99,"shipping_amt":0.99,"total_amt":25.98}]' \
https://www.tryhoard.com/api/v1/orders
For a large batch, gzip the JSON first:
gzip -c orders.json | curl -X POST \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/gzip" \
--data-binary @- \
https://www.tryhoard.com/api/v1/orders
Error responses
| Code | Error code | Meaning |
|---|
| 422 | invalid_json | Request body is not valid JSON |
| 422 | invalid_gzip | Content-Type is application/gzip but the body is not valid gzip |
| 422 | invalid_payload | Body is not an array of order hashes, or a row is missing order_number |
| 422 | empty_payload | The orders array is empty |
| 413 | payload_too_large | Request body exceeds 10 MB on the wire |
| 413 | decompressed_too_large | Decompressed gzip body exceeds 50 MB |
| 413 | too_many_rows | More than 50,000 orders in a single request |
Notes
- Hoard parses TCGplayer’s order export CSV and converts it to this JSON format
- First sync sends full order history (from January 2020)
- Subsequent syncs send the last 90 days
- Focused
refresh_orders tasks reuse the same upload endpoint after Hoard fetches updated orders
- Order upload is non-fatal. If it fails, the inventory sync still completes.
- Active Pull sessions keep their snapshot stable; refreshed orders that drift
out of eligibility are flagged in the Pull queue.
Upload order refunds
Upload parsed refund rows from TCGplayer’s order export. The request is
shape-validated synchronously and queued for upsert in a background job — the
response is 202 Accepted and the database write happens asynchronously.
Refund rows are upserted by (user_id, order_number), either creating new
orders or enriching existing ones with refund metadata.
POST /api/v1/order_refunds
Content-Type: application/json
The endpoint accepts both raw JSON and gzip-compressed JSON. For large
batches, set Content-Type: application/gzip and gzip the JSON body. The
server transparently decompresses gzip and falls back to raw bytes when the
body is not gzip-encoded.
Request body:
[
{
"order_number": "ORD-12345",
"buyer_name": "John Doe",
"product_amt": 24.99,
"shipping_amt": 0.99,
"total_amt": 25.98,
"order_date": "3/27/2026",
"status": "Refunded",
"refund_type": "full",
"refund_origin": "tcgplayer"
}
]
Response:
{"status": "accepted", "count": 1}
HTTP status is 202 Accepted — the server has validated the payload shape
and enqueued the upsert. The count field reflects the number of refund rows
in the request.
curl example
curl -X POST \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '[{"order_number":"ORD-12345","buyer_name":"John Doe","total_amt":25.98,"refund_type":"full","refund_origin":"tcgplayer"}]' \
https://www.tryhoard.com/api/v1/order_refunds
For a large batch, gzip the JSON first:
gzip -c refunds.json | curl -X POST \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/gzip" \
--data-binary @- \
https://www.tryhoard.com/api/v1/order_refunds
Error responses
| Code | Error code | Meaning |
|---|
| 422 | invalid_json | Request body is not valid JSON |
| 422 | invalid_gzip | Content-Type is application/gzip but the body is not valid gzip |
| 422 | invalid_payload | Body is not an array of objects, or a row is missing order_number |
| 422 | empty_payload | The refunds array is empty |
| 413 | payload_too_large | Request body exceeds 10 MB on the wire |
| 413 | decompressed_too_large | Decompressed gzip body exceeds 50 MB |
| 413 | too_many_rows | More than 50,000 refund rows in a single request |
Upload order line items
Upload parsed line items for existing orders. The request is shape-validated
synchronously and queued for upsert in a background job — the response is
202 Accepted and the database write happens asynchronously. Items are
upserted by (order_id, sku_id). Items whose order_number has no matching
order owned by the user are silently skipped, and multiple sku-less rows per
order are allowed.
POST /api/v1/order_items
Content-Type: application/json
The endpoint accepts both raw JSON and gzip-compressed JSON. The same gzip
fallback rules as /api/v1/orders apply.
Request body:
[
{
"order_number": "ORD-12345",
"product_name": "Lightning Bolt",
"product_line": "Magic",
"condition": "Near Mint",
"set_name": "Alpha",
"rarity": "C",
"quantity": 2,
"sku_id": 12345,
"main_photo_url": "https://example.com/bolt.jpg"
}
]
Response:
{"status": "accepted", "count": 1}
curl example
curl -X POST \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '[{"order_number":"ORD-12345","product_name":"Lightning Bolt","sku_id":12345,"quantity":2}]' \
https://www.tryhoard.com/api/v1/order_items
For a large batch, gzip the JSON first:
gzip -c items.json | curl -X POST \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/gzip" \
--data-binary @- \
https://www.tryhoard.com/api/v1/order_items
Error responses
| Code | Error code | Meaning |
|---|
| 422 | invalid_json | Request body is not valid JSON |
| 422 | invalid_gzip | Content-Type is application/gzip but the body is not valid gzip |
| 422 | invalid_payload | Body is not an array of objects |
| 422 | empty_payload | The items array is empty |
| 413 | payload_too_large | Request body exceeds 10 MB on the wire |
| 413 | decompressed_too_large | Decompressed gzip body exceeds 50 MB |
| 413 | too_many_rows | More than 50,000 line items in a single request |
Upload order shipping
Upload shipping enrichment (carrier, address, tracking, weight) for existing
orders. The request is shape-validated synchronously and queued for a bulk
SQL update in a background job — the response is 202 Accepted and the
database write happens asynchronously. Updates are keyed on
(user_id, order_number); unknown order numbers are silently skipped.
POST /api/v1/orders/shipping
Content-Type: application/json
The endpoint accepts both raw JSON and gzip-compressed JSON. The same gzip
fallback rules as /api/v1/orders apply.
Request body:
[
{
"order_number": "ORD-12345",
"shipping_method": "USPS First Class",
"city": "Portland",
"state": "OR",
"postal_code": "97201",
"tracking_number": "9400111899223100001234",
"item_count": 3,
"product_weight": 0.5
}
]
Response:
{"status": "accepted", "count": 1}
curl example
curl -X POST \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '[{"order_number":"ORD-12345","shipping_method":"USPS First Class","city":"Portland","state":"OR","postal_code":"97201","tracking_number":"9400111899223100001234"}]' \
https://www.tryhoard.com/api/v1/orders/shipping
For a large batch, gzip the JSON first:
gzip -c shipping.json | curl -X POST \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/gzip" \
--data-binary @- \
https://www.tryhoard.com/api/v1/orders/shipping
Error responses
| Code | Error code | Meaning |
|---|
| 422 | invalid_json | Request body is not valid JSON |
| 422 | invalid_gzip | Content-Type is application/gzip but the body is not valid gzip |
| 422 | invalid_payload | Body is not an array of objects, or a row is missing order_number |
| 422 | empty_payload | The shipping array is empty |
| 413 | payload_too_large | Request body exceeds 10 MB on the wire |
| 413 | decompressed_too_large | Decompressed gzip body exceeds 50 MB |
| 413 | too_many_rows | More than 50,000 shipping rows in a single request |
Upload seller feedback
Upload seller feedback ratings scraped from TCGplayer. Matches each item to an
existing order by order_number and stores the rating and comment.
Items with no matching order or ratings outside 1–5 are silently skipped.
POST /api/v1/order_feedbacks
Content-Type: application/json
Request body:
[
{
"order_number": "ORD-12345",
"rating": 5,
"comment": "Fast shipping, great packaging!"
}
]
Feedback object fields
| Field | Type | Required | Description |
|---|
order_number | string | Yes | TCGplayer order number to attach feedback to. Must match an existing order. |
rating | integer | Yes | Seller rating from 1 (lowest) to 5 (highest). |
comment | string | No | Optional buyer comment. |
Response:
{"status": "ok", "updated": 1}
The updated field is the number of orders that had feedback written to them.
curl example
curl -X POST \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '[{"order_number":"ORD-12345","rating":5,"comment":"Great seller!"}]' \
https://www.tryhoard.com/api/v1/order_feedbacks
Error responses
| Code | Error code | Meaning |
|---|
| 422 | invalid_json | Request body is not valid JSON |
| 422 | empty_payload | The feedback array is empty |