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

# Record a payment already received

> Record a MXN 1,160 bank transfer and handle a repeated request.

This recipe uses a Mexican MXN/IVA sale to demonstrate payment registration.
For other countries, adapt the currency and tax inputs using
[shared fields and country rules](/concepts/shared-fields).

**Case:** your customer already transferred MXN 1,160 to your bank. You want that
payment in gigstack. This operation records it; it does not charge a card or move money.

Use the customer from [Create a customer once](/recipes/customer).

## Register the transfer

```bash theme={null}
set -euo pipefail
curl --fail-with-body "$GIGSTACK_BASE_URL/payments/register" \
  -H "Authorization: Bearer $GIGSTACK_API_KEY" \
  -H 'Content-Type: application/json' \
  --data "$(jq -n --arg client "$CLIENT_ID" '{
    client: {id: $client},
    currency: "MXN",
    payment_form: "03",
    automation_type: "none",
    idempotency_key: "bank-transfer-order-1042",
    items: [{
      description: "One hour of consulting",
      product_key: "80101500",
      unit_key: "E48",
      unit_price: 1000,
      quantity: 1,
      taxes: [{type: "IVA", rate: 0.16, inclusive: false, withholding: false, factor: "Tasa"}]
    }]
  }')" > payment.json

PAYMENT_ID=$(jq -er '.data.id' payment.json)
export PAYMENT_ID
```

**Expected:** HTTP `201`; these selected response fields were observed in test mode:

```json theme={null}
{
  "success": true,
  "data": {
    "status": "succeeded",
    "livemode": false,
    "currency": "MXN",
    "subtotal": 1000,
    "taxes": 160,
    "total": 1160
  }
}
```

`unit_price` uses currency units: `1000` means MXN 1,000. `rate: 0.16` means 16%.
The API calculates the total from the items. The example tax treatment is illustrative;
use the taxes and product classification appropriate to the actual sale.

## Prevent a second payment record

Reuse the **same** `idempotency_key` for the same transfer. In the verified staging
behavior, repeating it returns HTTP **`400`**, with:

```json theme={null}
{
  "success": false,
  "error": {
    "code": "resource_conflict",
    "message": "Idempotency key error",
    "details": "Idempotency key already exists (id: payment_EXAMPLE)"
  }
}
```

Fetch the existing payment and reconcile it with the transfer. Do not generate a new key
just to make the error disappear. A different payment needs its own key.

## Choose automation deliberately

`automation_type: "none"` records this payment without requesting invoice automation.
For a payment against an existing PPD invoice, follow [Paid later](/recipes/paid-later).
Supplying `ppd_invoice_id` activates complement handling even if `automation_type` is `none`.

If the customer has **not** paid, use [Create a payment request](/reference/createPaymentsRequest)
instead. A created checkout link is not proof of payment.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.