# 서버에서 보내기

> 시크릿 API 키로 백엔드, 스크립트, 연동에서 제출을 생성하세요.

백엔드, 크론 작업, 연동은 브라우저와 같은 엔드포인트로 POST할 수 있습니다. 시크릿 API 키를 추가하면 Ikiform이 여러분이 보낸 POST임을 알 수 있습니다.

## 시크릿 키 만들기

1. 대시보드에서 **API keys**를 열고 **secret** 키를 만드세요.
2. `submissions:write` 스코프를 부여하세요. 같은 키로 [REST API](https://ikiform.com/ko/docs/api.md)의 데이터도 읽을 때만 `submissions:read`와 `forms:read`를 추가하세요.
3. 키를 복사하세요. `ik_sk_`로 시작하며 한 번만 표시됩니다. Ikiform은 해시만 저장합니다.

## 제출 보내기

**Node** (`submit.ts`)

```ts
const response = await fetch("https://ikiform.com/f/frm_xxxxxxxxxxxxxxxx", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    Authorization: `Bearer ${process.env.IKIFORM_SECRET_KEY}`,
    "Idempotency-Key": order.id,
  },
  body: JSON.stringify({ email: order.email, plan: order.plan }),
});

const result = await response.json();
if (!result.ok) throw new Error(`${result.error.code}: ${result.error.message} (${result.request_id})`);
```

**curl** (`Terminal`)

```bash
curl https://ikiform.com/f/frm_xxxxxxxxxxxxxxxx \
  -H "Authorization: Bearer $IKIFORM_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: order_1234" \
  -d '{"email":"ada@example.com","plan":"team"}'
```

**Python** (`submit.py`)

```python
import os

import requests

response = requests.post(
    "https://ikiform.com/f/frm_xxxxxxxxxxxxxxxx",
    json={"email": "ada@example.com", "plan": "team"},
    headers={
        "Authorization": f"Bearer {os.environ['IKIFORM_SECRET_KEY']}",
        "Idempotency-Key": "order_1234",
    },
    timeout=10,
)
result = response.json()
if not result["ok"]:
    raise RuntimeError(f"{result['error']['code']}: {result['error']['message']}")
```

## 시크릿 키를 쓰면 달라지는 점

| 검사 | 키 없음 | 시크릿 키 사용 |
| --- | --- | --- |
| 허용 도메인 | `Origin` 또는 `Referer`와 비교 | 건너뜀 |
| Ikiform 사람 확인 | 켜져 있으면 필수 | 건너뜀 |
| 직접 발급한 Turnstile 키 | 토큰 필수 | 여전히 토큰 필수 |
| 레이트 리밋 | 방문자 IP와 폼별 | 서버의 IP 기준으로 여전히 적용 |
| 필드 검증과 스팸 점수 | 실행 | 실행 |

다른 워크스페이스의 키, 폐기된 키, `submissions:write`가 없는 시크릿 키는 `403 forbidden`을 받습니다. 형식이 잘못된 `Authorization` 헤더도 무시하지 않고 거부하므로, 오타 때문에 익명 POST로 조용히 바뀌는 일은 없습니다.

> 서버에서 보낸 POST는 모두 서버의 IP 주소에서 오므로, Ikiform의 방문자별 레이트 리밋이 모든 방문자를 합쳐서 셉니다. Standard 프리셋은 IP와 폼별로 분당 5건을 허용하며, 트래픽이 많은 사이트는 이 한도에 닿을 수 있습니다. 가능하면 브라우저에서 POST하거나, 서버를 거쳐 보내는 폼에는 Relaxed 또는 Custom [레이트 리밋](https://ikiform.com/ko/docs/rate-limits.md)을 고르세요.

## 퍼블리셔블 키

퍼블리셔블 키(`ik_pub_`)는 브라우저용입니다. 제출만 할 수 있고, 키에 등록한 도메인에서만 작동합니다. 다른 사이트에서 퍼블리셔블 키로 POST하면 `403 origin_not_allowed`를 받습니다. 사람 확인이나 폼 자체의 허용 도메인은 건너뛰지 않습니다.

> 시크릿 키를 브라우저 코드, 모바일 앱, 공개 저장소에 절대 넣지 마세요. 유출되면 대시보드에서 폐기하세요.

## 재시도

서버는 재시도합니다. 주문 ID처럼 제출하는 대상에 대해 변하지 않는 `Idempotency-Key`를 보내면, 재시도해도 중복을 만들지 않고 첫 응답을 그대로 돌려줍니다. [멱등성](https://ikiform.com/ko/docs/frameworks.md#idempotency)을 참고하세요.
