Skip to main content

Reporting orders: the server API

Base URL: your s2s_endpoint_base (e.g. https://realry.com/api/v1/direct). Every request is a POST with a JSON body and the three signature headers below.

Signing a request

Every call carries three headers:
HeaderValue
X-Merchant-Keyyour api_key
X-Signature-Timestampthe current unix time in seconds (a whole number)
X-SignatureHMAC_SHA256(timestamp + body, hmac_secret), as hex
To build the signature: take the timestamp, glue the exact JSON body directly onto the end of it (no space, no separator), and HMAC-SHA256 that string with your hmac_secret.
Build your JSON body once, sign that exact text, and send that exact text. If you re-encode the body after signing (even just reordering keys), the signature won’t match.
What the server checks — any failure returns 401:
  • All three headers are present.
  • The timestamp is a whole number and within 5 minutes of our clock. (Keep your server clock synced with NTP.)
  • Your api_key is active.
  • The signature matches.
Your key is tied to your account, so you never name a seller in the body — we already know it’s you.

The four events

You report an order’s life with these calls. All take merchant_order_id (your order id) and a unique event_id (see Safe retries below).

1. Order paid — POST /conversions

Send this the moment payment completes (card capture, or the bank-deposit confirmation for virtual-account orders — see Virtual-account orders below).
{
  "merchant_order_id": "order-1",
  "event_id": "evt-1",
  "amount": 49900,
  "currency": "KRW",
  "cb_aev": "ABC123",
  "product_name": "Silk Blouse",
  "items": [{ "item_id": "sku-7", "name": "Silk Blouse", "price": 49900, "quantity": 1 }]
}
FieldRequiredNotes
merchant_order_idyesyour order id (same as the pixel transaction_id)
event_idyesunique per call; used to make retries safe
amountyesorder total; a number, 0 or greater
currencyyes3-letter code, e.g. KRW
cb_aevnothe click id you saved; omit it and the order isn’t credited to a creator
product_namenoshown in the creator’s dashboard; falls back to items[0].name, else left blank
itemsnoline items, for your own records
sub_idnoyour own click/tracking reference — we echo it back everywhere so you can reconcile
Response:
{
  "data": {
    "merchant_order_id": "order-1",
    "transaction_id": "stylmatch:<your_seller_id>:order-1",
    "status": "CONFIRMED",
    "net_amount": 49900,
    "refunded_amount": 0,
    "currency": "KRW"
  }
}
net_amount is the order total minus any refunds. transaction_id is our own internal reference — you don’t need to parse it; always match orders by your merchant_order_id.

2. Partial refund — POST /conversions/partial

Reduces the order by refund_amount (a partial cancel or return).
{ "merchant_order_id": "order-1", "event_id": "evt-2", "refund_amount": 10000 }
Status becomes PARTIALLY_CANCELLED and net_amount drops. refund_amount must be between 0 and the current net_amount.

3. Full cancel — POST /conversions/cancel

{ "merchant_order_id": "order-1", "event_id": "evt-3" }
Sets net_amount to 0, status CANCELLED, and reverses any commission.

4. Don’t credit this order — POST /conversions/decline

Use this when you determine one of your own paid channels actually won the sale, not the creator. A declined order is dropped from settlement and never invoiced.
{ "merchant_order_id": "order-1", "event_id": "evt-4", "reason": "own_google_ads_last_click" }
Status becomes DECLINED, net_amount 0. reason is a free-text note for your own records.

Safe retries — event_id

Give every call a unique event_id. If a request times out and you retry it, reuse the same event_id — we recognize it and won’t double-count. Retrying is always safe.

Virtual-account orders

For virtual-account (bank-transfer) payments, money isn’t real until the customer deposits. So:
  • Don’t send the order report when the order is created.
  • Send it when your PG’s deposit-confirmed webhook fires (PortOne / Toss / NICE). That’s the moment to call POST /conversions.
  • If the deadline passes with no deposit, simply never send it. No cancel call is needed — an order we never heard about never settles.