Skip to content
StraventaDocs
Now in Sandbox.

Record an order the seller took themselves (draft)

POST
/v1/marketplace/orders/admin/draft

A DRAFT ORDER IS AN ORDER. It reserves stock, locks a promo the same way a storefront placement does, and gets a payment intent — the response's pay_url is what the seller composes into the link they send the buyer over WhatsApp or reads out at the counter, and it is the ENTIRE handoff to the checkout app, exactly as payment_shortcode is on the buyer-facing placement. A CLOSED STOREFRONT DOES NOT BLOCK THIS ROUTE. storefront_closed is the buyer placement's refusal, not this one's: a seller who has switched the shop manually closed is not thereby forbidden from writing down a sale they took themselves — that is the whole reason this route exists rather than telling every seller who takes phone orders to reopen the storefront first. THE BODY CARRIES NO LINE PRICE, for the same reason the buyer's body carries none: unit_cents, line_total_cents, subtotal_cents, shipping_cents, tax_cents and total_cents are refused with 400 unexpected_price_field wherever they appear, including inside lines[]. A seller discounts through manual_discount_cents WITH A REASON, never by naming a price — the same split unexpected_price_field polices on the storefront route. manual_discount_cents > 0 REQUIRES a non-empty manual_discount_reason — absent or "" on a positive discount is 400 manual_discount_reason_required. The amount is WHOLE RUPIAH, NOT SEN (ADR-2026-09-22), and it is INCLUDED IN, not added beside, discount_cents on the stored order: the totals identity total = subtotal - discount + tax + shipping stays literally true whether the discount came from a promo code, a hand-typed amount, or both at once. The column records how much OF the discount the seller granted by hand rather than by a code. THE SHIPPING BLOCK IS BYTE-IDENTICAL to the buyer placement's — same component, same rules, same invalid_shipping refusal — because a draft order ships exactly the way a storefront order does. client_operation_id IS THE SAME PLACEMENT IDEMPOTENCY KEY the storefront route uses, scoped to this store: a repeat with the same key and the same body replays the original response byte-for-byte; the same key with a different body is 409 idempotency_key_mismatch; a concurrent repeat is 409 idempotency_in_progress. AUDIT-LOGGED IN THE SAME TRANSACTION as the order write, carrying the acting user — a hand-entered order and a hand-typed discount are both an employee's decision on a merchant's behalf, and the record of who made it does not get to be a best-effort side write. The fence comes from the STORE ROW store_id resolves to, exactly as the § T issue routes read theirs: the permission marketplace.order.write is checked at merchant:<id>:marketplace:orders, never against a claim on the request.

Authorization

bearerAuth
AuthorizationBearer <token>

In: header

Request Body

application/json

TypeScript Definitions

Use the request body type in TypeScript.

Response Body

application/json

application/json

application/json

application/json

application/json

application/json

application/json

application/json

application/json

curl -X POST "https://sandbox.505pay.link/v1/marketplace/orders/admin/draft" \  -H "Content-Type: application/json" \  -d '{    "store_id": "01916b2a-f3c0-7000-0000-0000000000s1",    "client_operation_id": "console-draft-7f3a91c4",    "buyer": {      "email": "[email protected]",      "name": "Siti Rahmawati",      "phone": "+628123456789"    },    "lines": [      {        "variant_id": "01916b2a-f3c0-7000-0000-0000000000aa",        "quantity": 2      }    ],    "manual_discount_cents": 0,    "manual_discount_reason": ""  }'
{
  "order": {
    "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
    "order_number": "string",
    "store_name": "string",
    "subtotal_cents": 0,
    "tax_cents": 0,
    "commission": {
      "bps": 500,
      "base_cents": 170000,
      "commission_cents": 8500,
      "net_to_seller_cents": 161500,
      "currency": "IDR",
      "state": "accrued",
      "source": "default"
    },
    "status": "pending",
    "payment_status": "pending",
    "total_cents": 0,
    "currency": "str",
    "buyer_name": "string",
    "buyer_email": "string",
    "platform_fee_status": "unmetered",
    "platform_fee_cents": 0,
    "shipping_cents": 0,
    "shipping_method_name": "string",
    "shipping_address": {
      "recipient_name": "string",
      "phone": "string",
      "street": "string",
      "city": "string",
      "province": "string",
      "postal_code": "string",
      "note": "string"
    },
    "discount_cents": 0,
    "promo_code": "string",
    "placed_at": "2019-08-24T14:15:22Z",
    "captured_at": "2019-08-24T14:15:22Z",
    "created_at": "2019-08-24T14:15:22Z",
    "origin": "storefront",
    "manual_discount_cents": 0,
    "manual_discount_reason": "string"
  },
  "pay_url": "string"
}
{
  "error": "not_found",
  "message": "resource not found",
  "request_id": "01916b2a-f3c0-7000-0000-0000000000ff"
}
{
  "error": "not_found",
  "message": "resource not found",
  "request_id": "01916b2a-f3c0-7000-0000-0000000000ff"
}
{
  "error": "not_found",
  "message": "resource not found",
  "request_id": "01916b2a-f3c0-7000-0000-0000000000ff"
}
{
  "error": "not_found",
  "message": "resource not found",
  "request_id": "01916b2a-f3c0-7000-0000-0000000000ff"
}
{
  "error": "not_found",
  "message": "resource not found",
  "request_id": "01916b2a-f3c0-7000-0000-0000000000ff"
}
{
  "error": "body_too_large",
  "message": "request body exceeds the 65536-byte limit",
  "request_id": "01916b2a-f3c0-7000-0000-0000000000ff"
}
{
  "error": "not_found",
  "message": "resource not found",
  "request_id": "01916b2a-f3c0-7000-0000-0000000000ff"
}
{
  "error": "rate_limit_exceeded",
  "message": "too many requests",
  "request_id": "01916b2a-f3c0-7000-0000-0000000000ff"
}

Was this page helpful?