Skip to main content

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

FieldTypeRequiredDescription
order_numberstringYesTCGplayer order number. Used as the unique key for upserts.
buyer_namestringNoBuyer’s display name from the order.
order_datestringNoOrder date as parsed from TCGplayer CSV (e.g., "3/27/2026").
statusstringNoOrder status from TCGplayer (e.g., "Completed", "Cancelled").
product_amtnumberNoProduct subtotal in USD.
shipping_amtnumberNoShipping amount in USD.
total_amtnumberNoTotal 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

CodeError codeMeaning
422invalid_jsonRequest body is not valid JSON
422invalid_gzipContent-Type is application/gzip but the body is not valid gzip
422invalid_payloadBody is not an array of order hashes, or a row is missing order_number
422empty_payloadThe orders array is empty
413payload_too_largeRequest body exceeds 10 MB on the wire
413decompressed_too_largeDecompressed gzip body exceeds 50 MB
413too_many_rowsMore 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

CodeError codeMeaning
422invalid_jsonRequest body is not valid JSON
422invalid_gzipContent-Type is application/gzip but the body is not valid gzip
422invalid_payloadBody is not an array of objects, or a row is missing order_number
422empty_payloadThe refunds array is empty
413payload_too_largeRequest body exceeds 10 MB on the wire
413decompressed_too_largeDecompressed gzip body exceeds 50 MB
413too_many_rowsMore 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

CodeError codeMeaning
422invalid_jsonRequest body is not valid JSON
422invalid_gzipContent-Type is application/gzip but the body is not valid gzip
422invalid_payloadBody is not an array of objects
422empty_payloadThe items array is empty
413payload_too_largeRequest body exceeds 10 MB on the wire
413decompressed_too_largeDecompressed gzip body exceeds 50 MB
413too_many_rowsMore 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

CodeError codeMeaning
422invalid_jsonRequest body is not valid JSON
422invalid_gzipContent-Type is application/gzip but the body is not valid gzip
422invalid_payloadBody is not an array of objects, or a row is missing order_number
422empty_payloadThe shipping array is empty
413payload_too_largeRequest body exceeds 10 MB on the wire
413decompressed_too_largeDecompressed gzip body exceeds 50 MB
413too_many_rowsMore 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

FieldTypeRequiredDescription
order_numberstringYesTCGplayer order number to attach feedback to. Must match an existing order.
ratingintegerYesSeller rating from 1 (lowest) to 5 (highest).
commentstringNoOptional 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

CodeError codeMeaning
422invalid_jsonRequest body is not valid JSON
422empty_payloadThe feedback array is empty