통합 가이드: 연결 → 승인 → 지출 → 정산
이 가이드는 에이전트 결제의 전체 수명주기를, 에이전트를 처음 연결하는 데서 정산된 영수증까지 따라갑니다. 퀵스타트를, 재시도와 충돌 상황에서 흐름을 안전하게 만드는 순서와 멱등성 보장, 실패 처리로 확장합니다. Tidal의 승인된 결제 워크플로에 근거합니다.
네 단계
**연결(Connect)**은 에이전트와 그 키를 확립합니다. createAgent(userId, agentId)를 호출하면 에이전트
키가 당신의 키 저장소에서 생성되고 그 공개 절반만 Tidal 디렉터리에 등록됩니다. 이것은 당신의 식별자에
대해 멱등하며, 재시도가 두 번째 키를 찍어내는 일이 없습니다.
**승인(Authorize)**은 한도 안에서 사용자의 동의를 얻습니다. requestAuthorization({ limits, currency, expiry })를 호출하고 반환된 App Link / QR 페이로드 — 공개 라우팅 핸들뿐 — 를 사용자에게 제시합니다.
사용자는 자신의 Tidal 지갑에서 한도와 당신 애플리케이션의 검증된 신원을 검토하고 승인하며, 그들의
마스터 키가 예산 계좌를 준비합니다. 자금을 넣고, 필요하면 RLUSD 신뢰선을 설정하며, 2-of-2 서명자 목록을
설치합니다. 활성화되었음은 폴링이나 authorization.activated 웹훅으로 알게 됩니다.
**지출(Spend)**은 단일 멱등 호출로 구동되는 결제별 흐름입니다. 고유한 idempotencyKey를 제공하면, SDK와
플랫폼이 그 신원을 정책 승인, 에이전트 서명, 공동서명, 조립, 제출, 최종성까지 관통해 이어갑니다. 아래에서
순서대로 설명합니다.
**정산(Settle)**은 원장이 하는 일입니다. 두 개의 서명이 담긴 직접 XRP 또는 RLUSD Payment가 검증되고,
당신은 묶인 영수증을 받습니다. 정산은 최종입니다.
결제 순서
결제 호출은 고정된, fail-closed 워크플로를 돌립니다. 각 단계는 충돌이나 시간 초과가 이중 지출 대신 올바르게 재개되도록 내구성 있게 순서가 매겨집니다.
sequenceDiagram
autonumber
participant A as 에이전트 백엔드<br/>(SDK)
participant P as 정책·위험
participant K as 당신의 KeyStore
participant C as Tidal 공동서명자<br/>+ 지갑 실행
participant X as XRP 원장
A->>A: 입력 검증, 멱등 신원 확보
A->>A: 소유자 의도 + 정확한 직접 Payment 요청 구성
A->>P: 정책 결정 요청
alt 거부 또는 챌린지
P-->>A: 거부 / 챌린지 — 중단 (아직 서명 없음)
else 승인
P-->>A: 서명된 정책 승인
A->>A: 서명 프리이미지 준비(wallet-core), 거래 동결
A->>A: 오퍼레이션 예약, 승인 + 동결 거래 바인딩, 서명 펜스 설정
A->>K: 동결 프리이미지에 대해 에이전트 절반 서명
K-->>A: 에이전트 Signer 기여
A->>C: 서명 요청 제출(에이전트 절반 + 승인)
C->>C: 승인·필드·Payment 전용 검증, HSM 공동서명
C-->>A: 두 번째 Signer 기여
A->>A: 2-of-2 조립, 제출 전 바이트 + 트랜잭션 ID 보존
A->>X: 한 번 제출
X-->>A: 검증된 최종성
A-->>A: 묶인 영수증 반환
end이 순서에서 두 가지를 몸에 새겨 둘 가치가 있습니다.
첫째, 정책 승인 전까지 에이전트 서명은 존재하지 않습니다. 거부와 챌린지는 3~4단계에서, 당신의 키 저장소에 서명을 요청하기 전에 일어납니다. 거부된 결제는 그 누구에 의해서도 진정으로 서명되지 않습니다.
둘째, 서명에는 되돌아올 수 없는 지점이 있습니다. 서명 펜스 이전에는, 무언가 실패하면 오퍼레이션을 깨끗이 놓아줄 수 있습니다. 서명 요청이 디스패치된 순간부터는 서명 자료가 존재할 수 있으므로, 재시도는 같은 오퍼레이션, 같은 승인, 같은 동결 거래를 유지해야 합니다. 정확한 상태를 재개하거나 명시적 대사에 들어갈 뿐, 결코 두 번째 서명이나 제출 경로를 시작하지 않습니다. 거래가 제출되었을 수 있는 이후에는, 자동 재시도가 결코 재제출하지 않습니다. 모호한 제출은 묶인 트랜잭션 ID로 대사합니다.
실전에서의 멱등성
idempotencyKey는 필수이며, 개발자가 생성하고, 엔트로피가 높으며, 에이전트 안에서 고유해야 합니다.
플랫폼은 이를 정규 요청 다이제스트와 단일 오퍼레이션에 묶습니다.
- 같은 키, 같은 정규 요청 → 같은 오퍼레이션을 재개하거나 반환.
- 같은 키, 다른 요청 →
IdempotencyConflictError. - 완료된 재시도는 정책, 서명, 공동서명, 제출의 어떤 부수 효과도 내지 않고 같은 영수증을 반환.
- 동시 호출자는 같은 완료 결과나
ConcurrentExecutionError를 받을 뿐, 두 번의 실행은 결코 없음.
당신 코드를 위한 실전 규칙: 논리적 결제마다 키를 한 번 생성해 보존하고, 그 결제의 모든 재시도에 같은 키를 재사용하세요. 오류 시 키를 다시 생성하지 마세요. 그것이 바로 중복을 만드는 방법입니다.
결과 다루기
서버 SDK는 안정적인, 타입이 지정된 오류를 내보냅니다. 상태 코드를 들여다보는 대신 타입으로 다루세요. 타입화된 사유가 없는 상태 코드는 의도적으로 계약 위반으로 취급되는데, 여러 결제 상태가 하나의 HTTP 상태를 공유하기 때문입니다.
| 오류 | 의미 | 대응 |
|---|---|---|
AuthenticationError | 요청 자격 증명이 무효. | 자격 증명/서명을 고침. 무작정 재시도하지 않음. |
CredentialRevokedError | API 자격 증명이 철회됨. | 자격 증명을 회전. |
PolicyDeniedError | 한도나 정책 규칙 위반. 서명되지 않음. | 사유를 드러냄. 그대로 재시도하지 않음. |
ChallengePendingError | 사용자가 챌린지에 답해야 함. | 챌린지를 해소한 뒤 같은 오퍼레이션 재개. |
InsufficientBudgetError | 예산 계좌가 예비금+수수료 위로 감당 불가. | 충전을 유도, 자금 조달 후 재시도. |
AgentKeyConflictError | 같은 에이전트 신원, 다른 공개키. | 조사. 새 키를 강제하지 않음. |
IdempotencyConflictError | 같은 멱등 키, 다른 요청. | 키/요청 짝을 고침. |
ConcurrentExecutionError | 같은 오퍼레이션의 다른 실행이 진행 중. | 기다렸다 오퍼레이션을 읽음. 두 번째를 띄우지 않음. |
CoSignerUnavailableError | 공동서명자 일시 불가(retryable: true). | 백오프로 재시도, 같은 멱등 키. |
LedgerWindowExpiredError | 서명 원장 윈도가 지남. | 새 시도에는 새 승인이 필요. |
ReconciliationRequiredError | 모호한 제출. | 묶인 트랜잭션 ID로 대사. 재제출하지 않음. |
WorkflowAbortedError | 확정 전에 워크플로가 중단됨. | 논리적 결제를 다시 시작해도 안전. |
SDK가 의지하는 HTTP 매핑: 멱등/동시성 충돌과 RECONCILIATION_REQUIRED에는 409, 정책 거부·챌린지
대기·예산 부족에는 422, 공동서명자 불가에는 retryable: true와 함께 503, 같은 오퍼레이션이 아직
진행 중이라 폴링·재개 가능할 때는 202. 모든 오류 봉투는 명시적 retryable 값을 지닙니다.
초안 — 확정 예정. 퀵스타트에서 짚었듯, 단일 호출
agent.pay()상태 기계가 목표입니다. 현재 서버 SDK는 이 같은 워크플로와 멱등 저널 위에서 검토된 구성 요소인agent.initiatePayment(input)과agent.getPayment(operationId)를 출시합니다. 챌린지는 initiation에서challenge_pending상태로 드러납니다. 위의 수명주기와 보장이 계약이며, 정확한 표면은pay()로 수렴하고 있습니다.
웹훅
폴링 대신, 관심 있는 이벤트를 구독하세요. 사실(fact)은 각기 하나의 소유자를 갖지만, 모두 하나의 웹훅 채널로 전달됩니다.
authorization.requested,authorization.approved,authorization.revoked,challenge.raised,payment.denied— 정책 권위체로부터.authorization.activated(서명자 목록이 원장에서 관측된 뒤),agent.created,agent.key_rotated,payment.settled(검증된 최종성 뒤) — Tidal 사실, 같은 채널로 전달.
각 전달은 독립된 웹훅 시크릿으로 T54-Webhook-Id, T54-Webhook-Timestamp, T54-Webhook-Signature
(HMAC-SHA256 over id.timestamp.정확한-본문-바이트)에 걸쳐 서명됩니다. 전달은 최소 한 번(at least once)
이므로 이벤트 ID로 중복을 제거하되, 서명·타임스탬프 윈도·봉투가 검증된 뒤에만 하세요. 서버 SDK는
서버 전용 진입점에서 이를 올바르게 수행하는 verifyWebhook 헬퍼를 내보냅니다. 검증을 직접 짜지 말고
이것을 쓰세요.