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

# Payment Callback

> Thin wrapper: release the payment dedup key on ANY processing failure.

`_payment_callback_impl` sets `request.state.payment_dedup_key` right
after it wins the Redis SET NX. If the impl raises before its session
commits (FX miss 503, currency mismatch 400, tx-not-found 404 race, DB
outage, ...), the key must be deleted — otherwise the provider's retry
gets `{"duplicate": true}` for 24h while the deposit stays PENDING and
cashier-source txs can't be approved manually (DEP-1, money review
2026-06-09). Releasing is always safe: the FOR UPDATE +
`status == "APPROVED"` check inside is the authoritative double-credit
guard; the Redis key is load-shedding only. Mirrors the release pattern
in routes/payouts.py (E6).

The key is RETAINED on success and on the already-approved
short-circuit — both return normally, so no release happens here.



## OpenAPI

````yaml /openapi.json post /transactions/payment-callback
openapi: 3.1.0
info:
  title: Slate API
  version: 1.0.0
  description: Trading infrastructure API.
servers:
  - url: https://api.{your-broker}.slate-labs.com
    variables:
      your-broker:
        default: broker
security: []
tags:
  - name: Authentication
  - name: API Tokens
  - name: Customers
  - name: Accounts
  - name: Orders
  - name: Instruments & Groups
  - name: Transactions
  - name: Payments
  - name: Transfers
  - name: Risk
  - name: Workflow & CRM
  - name: Messaging
  - name: Integrations
  - name: Webhooks
  - name: Compliance
  - name: Promo codes
  - name: Reporting
  - name: Audit
  - name: Fraud & moderation
  - name: Broker settings
  - name: Users
  - name: Roles & Teams
  - name: Streams (SSE)
  - name: Simulator
  - name: Observability
  - name: Prop trading
paths:
  /transactions/payment-callback:
    post:
      tags:
        - Transactions
      summary: Payment Callback
      description: |-
        Thin wrapper: release the payment dedup key on ANY processing failure.

        `_payment_callback_impl` sets `request.state.payment_dedup_key` right
        after it wins the Redis SET NX. If the impl raises before its session
        commits (FX miss 503, currency mismatch 400, tx-not-found 404 race, DB
        outage, ...), the key must be deleted — otherwise the provider's retry
        gets `{"duplicate": true}` for 24h while the deposit stays PENDING and
        cashier-source txs can't be approved manually (DEP-1, money review
        2026-06-09). Releasing is always safe: the FOR UPDATE +
        `status == "APPROVED"` check inside is the authoritative double-credit
        guard; the Redis key is load-shedding only. Mirrors the release pattern
        in routes/payouts.py (E6).

        The key is RETAINED on success and on the already-approved
        short-circuit — both return normally, so no release happens here.
      operationId: payment_callback_transactions_payment_callback_post
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema: {}

````