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:
| Header | Value |
|---|
X-Merchant-Key | your api_key |
X-Signature-Timestamp | the current unix time in seconds (a whole number) |
X-Signature | HMAC_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 }]
}
| Field | Required | Notes |
|---|
merchant_order_id | yes | your order id (same as the pixel transaction_id) |
event_id | yes | unique per call; used to make retries safe |
amount | yes | order total; a number, 0 or greater |
currency | yes | 3-letter code, e.g. KRW |
cb_aev | no | the click id you saved; omit it and the order isn’t credited to a creator |
product_name | no | shown in the creator’s dashboard; falls back to items[0].name, else left blank |
items | no | line items, for your own records |
sub_id | no | your 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.