{"lexicon":1,"id":"money.atmosphere.payment.refund","defs":{"main":{"type":"procedure","description":"Refund a payment the calling app originated. Requires a service-auth JWT signed by the originator DID with lxm matching this NSID. Omit amountCents to refund the full remaining unrefunded amount.","input":{"encoding":"application/json","schema":{"type":"object","required":["paymentId"],"properties":{"paymentId":{"type":"string","maxLength":256},"amountCents":{"type":"integer","minimum":1,"description":"Refund amount in the smallest currency unit. Omit to refund the full remaining unrefunded amount."},"reasonCode":{"type":"string","knownValues":["requested_by_customer","duplicate","fraudulent"],"maxLength":32,"description":"Processor-aligned refund reason code."},"reason":{"type":"string","maxLength":512,"description":"Optional free-text reason surfaced in refund webhooks and dashboards."},"cancelSubscription":{"type":"boolean","description":"For subscription payments, also cancel the underlying subscription so it stops billing."},"idempotencyKey":{"type":"string","maxLength":256,"description":"Optional caller-supplied idempotency key. A repeated refund call with the same paymentId and idempotencyKey resolves to the existing refund instead of issuing a second processor refund."}}}},"output":{"encoding":"application/json","schema":{"type":"object","required":["refundId","status","amountCents","amountRefundedTotalCents","paymentStatus"],"properties":{"refundId":{"type":"string","maxLength":256},"status":{"type":"string","knownValues":["pending","succeeded","failed","canceled","requires_action"],"maxLength":64,"description":"Processor refund status at creation time."},"amountCents":{"type":"integer","minimum":1,"description":"Amount of this refund in the smallest currency unit."},"amountRefundedTotalCents":{"type":"integer","minimum":0,"description":"Cumulative refunded amount for the payment in the smallest currency unit."},"paymentStatus":{"type":"string","maxLength":64}}}},"errors":[{"name":"PaymentNotFound","description":"Payment not found."},{"name":"NotOriginatingApp","description":"Caller is not the payment's originating app."},{"name":"RefundsNotAllowed","description":"Refunds are not available for this payment or app."},{"name":"AlreadyFullyRefunded","description":"The payment has already been fully refunded."},{"name":"DisputeOpen","description":"The payment has an open dispute; respond to the dispute instead of refunding."},{"name":"AmountTooLarge","description":"The requested amount exceeds the remaining refundable amount."},{"name":"RefundFailed","description":"The processor refund call failed."},{"name":"RateLimited","description":"Too many refund attempts; retry later."}]}}}