> ## Documentation Index
> Fetch the complete documentation index at: https://docs.tryaeris.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Reference

## Status 와 error code

Order status (`data.status`): `CONFIRMED`, `PARTIALLY_CANCELLED`, `CANCELLED`, `DECLINED`.

| HTTP  | 의미                                                                  |
| ----- | ------------------------------------------------------------------- |
| `200` | 적용 (또는 safe retry) — body 에 현재 주문 상태                                |
| `401` | Auth 실패 — header 누락, timestamp 만료, signature 불일치, 또는 inactive key   |
| `422` | 잘못된 데이터 또는 불법 변경 (예: refund 가 order 보다 큼, cancel 된 order 에 confirm) |
| `409` | Write collision — 같은 `event_id` 로 retry                             |
| `429` | 요청 과다 — 느처주고 retry                                                  |

***

## 복사해서 바로 쓰는 서명 helper

각 helper 는 서버가 check 하는 것과 정확히 같은 방식으로 signature 계산. 공통 규칙: **body 를 한 번 serialize 하고, 그 exact string 을 서명하고, 그 exact bytes 를 보내기.**

<CodeGroup>
  ```php PHP theme={"dark"}
  <?php
  function signAndPost(string $base, string $apiKey, string $secret, string $path, array $payload): array
  {
      $ts   = (string) time();
      $body = json_encode($payload, JSON_UNESCAPED_UNICODE); // serialize ONCE
      $sig  = hash_hmac('sha256', $ts . $body, $secret);

      $ch = curl_init($base . $path);
      curl_setopt_array($ch, [
          CURLOPT_POST           => true,
          CURLOPT_POSTFIELDS     => $body,   // the SAME bytes we signed
          CURLOPT_RETURNTRANSFER => true,
          CURLOPT_HTTPHEADER     => [
              'Content-Type: application/json',
              'X-Merchant-Key: ' . $apiKey,
              'X-Signature-Timestamp: ' . $ts,
              'X-Signature: ' . $sig,
          ],
      ]);
      $res  = curl_exec($ch);
      $code = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
      curl_close($ch);

      return ['status' => $code, 'body' => json_decode($res, true)];
  }

  $out = signAndPost('https://realry.com/api/v1/direct', 'mk_your_key', 'your_hmac_secret',
      '/conversions', [
          'merchant_order_id' => 'order-1',
          'event_id'          => 'evt-1',
          'amount'            => 49900,
          'currency'          => 'KRW',
          'cb_aev'            => $clickId,
          'product_name'      => 'Silk Blouse',
      ]);
  ```

  ```js Node.js theme={"dark"}
  import crypto from 'node:crypto';

  async function signAndPost(base, apiKey, secret, path, payload) {
    const ts = Math.floor(Date.now() / 1000).toString();
    const body = JSON.stringify(payload);           // serialize ONCE
    const sig = crypto.createHmac('sha256', secret).update(ts + body).digest('hex');

    const res = await fetch(base + path, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'X-Merchant-Key': apiKey,
        'X-Signature-Timestamp': ts,
        'X-Signature': sig,
      },
      body,                                          // the SAME string we signed
    });
    return { status: res.status, body: await res.json() };
  }

  await signAndPost('https://realry.com/api/v1/direct', 'mk_your_key', 'your_hmac_secret',
    '/conversions', {
      merchant_order_id: 'order-1',
      event_id: 'evt-1',
      amount: 49900,
      currency: 'KRW',
      cb_aev: clickId,
      product_name: 'Silk Blouse',
    });
  ```

  ```python Python theme={"dark"}
  import hashlib, hmac, json, time, urllib.request

  def sign_and_post(base, api_key, secret, path, payload):
      ts = str(int(time.time()))
      body = json.dumps(payload, separators=(",", ":"), ensure_ascii=False)  # serialize ONCE
      sig = hmac.new(secret.encode(), (ts + body).encode(), hashlib.sha256).hexdigest()

      req = urllib.request.Request(
          base + path,
          data=body.encode(),
          method="POST",
          headers={
              "Content-Type": "application/json",
              "X-Merchant-Key": api_key,
              "X-Signature-Timestamp": ts,
              "X-Signature": sig,
          },
      )
      with urllib.request.urlopen(req) as r:
          return {"status": r.status, "body": json.loads(r.read())}

  sign_and_post("https://realry.com/api/v1/direct", "mk_your_key", "your_hmac_secret",
      "/conversions", {
          "merchant_order_id": "order-1",
          "event_id": "evt-1",
          "amount": 49900,
          "currency": "KRW",
          "cb_aev": click_id,
          "product_name": "Silk Blouse",
      })
  ```

  ```bash cURL theme={"dark"}
  BASE="https://realry.com/api/v1/direct"
  API_KEY="mk_your_key"; SECRET="your_hmac_secret"

  TS=$(date +%s)
  BODY='{"merchant_order_id":"order-1","event_id":"evt-1","amount":49900,"currency":"KRW","cb_aev":"ABC123","product_name":"Silk Blouse"}'
  SIG=$(printf '%s' "${TS}${BODY}" | openssl dgst -sha256 -hmac "$SECRET" | sed 's/^.* //')

  curl -sS -X POST "$BASE/conversions" \\
    -H "X-Merchant-Key: $API_KEY" \\
    -H "X-Signature-Timestamp: $TS" \\
    -H "X-Signature: $SIG" \\
    -H "Content-Type: application/json" \\
    --data "$BODY"
  ```
</CodeGroup>

<Warning>
  **`401 invalid_signature` 에서 막힌다면?** 거의 항상 서명한 bytes 와 보낸 bytes 가 달라서 — 보통 서명 후에 body 가 re-encode 되거나 key 순서가 바뀌면 이런 일 생김. Body 를 한 번 만들고, 서명하고, 변형 없이 보내기.
</Warning>

***

문의? Aeris partner 담당자에게 연락. 항상 sandbox key 로 먼저 테스트 후 live credential 요청.
