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

# Upsert payments

> Create or update up to 100 merchant payment configurations by id in one request.

Send an array of payments. Each item creates a payment when its `id` is new, or updates the existing payment when it already belongs to the merchant on the access token. `id` is the Fire spark payment UUID and is required on every item. Send only the fields to change.

> [!NOTE]
>
> Requires an access token with the `payments:write` scope. See
> [Token](https://firespark.cloud/docs/integrations-api/oauth/token/post.md) to obtain a token.

`merchant_id` and `env` come from the token. When creating, `payment_provider_id` and `payment_method_id` are required. The method must belong to that provider. Omitted `status` becomes `ACTIVE`. Omitted scope arrays mean every store, channel, brand, and fulfillment. Send `null` on an existing payment to return a scope to every id. `private_key` and `webhook_signature` are stored but omitted from the response.

Sending `config`, `rules`, or `conditions` replaces that field entirely. Omitting one leaves the stored value.

## Config

`config` is validated against the provider slug, method, and version on the catalog rows.

| Provider | Method | Version | `config` |
| - | - | - | - |
| `kushki` | `CARD`, `WALLET`, `PIN_PAD` | `1.0.0` | `public_key` and `private_key` required. `webhook_signature` optional. |
| `firespark` | `CASH` | `1.0.0` | `{}` |
| `firespark` | `REDEMPTION` | `1.0.0` | Only `logo_url` (optional URL). Any other key is rejected. |
| `yape` | `BANK_TRANSFER`, `PIN_PAD` | `1.0.0` | `{}` |
| `niubiz` | `PIN_PAD` | `1.0.0` | `{}` |

Any other provider, method, or version accepts a JSON object. On create, an omitted `config` is validated as `{}`.

A `firespark` `REDEMPTION` payment is one custom redemption source (vouchers, Yape, Masivo, and so on). The payment `name` and `config.logo_url` identify that source, so storefronts show them instead of the Fire spark provider logo. `logo_url` is public and is returned in responses and to the storefront.

```json theme={null}
{ "logo_url": "https://cdn.example.com/acme-rewards.png" }
```

For `kushki`:

```json theme={null}
{
  "public_key": "pk_test_123",
  "private_key": "sk_test_123",
  "webhook_signature": "whsec_123"
}
```

## Rules

`rules` is an array of inclusive order-total windows. Each item needs `minimum_order_value` and `maximum_order_value` (0 to 1,000,000). `[]` means there is no amount gate. An omitted `rules` on create is stored as `[]`.

```json theme={null}
[{ "minimum_order_value": 5, "maximum_order_value": 200 }]
```

## Conditions

`conditions` is an OR of AND groups: the outer array is OR, and each inner array is AND. `[]` means the payment is eligible whenever its scope matches. An omitted `conditions` on create is stored as `[]`.

Each condition needs `primitive`, `type`, `operator`, and `value`. Optional fields: `interpretation` (`client`, `server`, or `both`) and `invalidMessage`.

Checkout primitives you can send:

| `primitive` | `type` examples | `operator` examples |
| - | - | - |
| `currency` | `Order total` | `greater than or equal to`, `less than` |
| `number` | `Cart product count`, `Order includes product` | `equal to`, `greater than` |
| `boolean` | `Is anonymous order`, `Customer is anonymous` | `is`, `is not` |
| `string` | `Order includes product with tag` | `equal to`, `contains` |
| `enum` | `Payment method`, `Payment collect at`, `Payment status` | `is`, `is any of` |
| `custom` | `Store`, `Channel`, `Brand`, `Fulfillment` | `is`, `is not` |
| `custom` | `Stores`, `Channels`, `Brands`, `Fulfillments` | `is any of`, `is none of`, `is all of` |

`Order includes product` also needs `product_id`. `Order includes product with tag` also needs `tag`.

This example offers the payment when the order total is at least 10, or when the cart has 3 or more products:

```json theme={null}
[
  [
    {
      "primitive": "currency",
      "type": "Order total",
      "operator": "greater than or equal to",
      "value": 10
    }
  ],
  [
    {
      "primitive": "number",
      "type": "Cart product count",
      "operator": "greater than or equal to",
      "value": 3
    }
  ]
]
```

## Request

```bash theme={null}
curl -X PUT "https://firespark.cloud/api/integrations/v1/payments" \
  -H "Authorization: Bearer ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '[
    {
      "id": "3b1c8f2e-5a44-4d1b-9c0e-2f6a1d8b7e90",
      "payment_provider_id": "6f1c8f2e-5a44-4d1b-9c0e-2f6a1d8b7e90",
      "payment_method_id": "7c1c8f2e-5a44-4d1b-9c0e-2f6a1d8b7e90",
      "config": {
        "public_key": "pk_test_123",
        "private_key": "sk_test_123",
        "webhook_signature": "whsec_123"
      },
      "rules": [
        { "minimum_order_value": 5, "maximum_order_value": 200 }
      ],
      "conditions": [
        [
          {
            "primitive": "currency",
            "type": "Order total",
            "operator": "greater than or equal to",
            "value": 10,
            "interpretation": "both",
            "invalidMessage": "Minimum order is 10"
          }
        ]
      ],
      "store_ids": ["downtown"],
      "channel_ids": ["app"],
      "brand_ids": ["0001"],
      "fulfillment_ids": ["delivery"],
      "store_label_ids": ["a1b2c3d4-e5f6-7890-abcd-ef1234567890"],
      "channel_label_ids": null,
      "brand_label_ids": null,
      "fulfillment_label_ids": null,
      "status": "ACTIVE"
    },
    {
      "id": "4c2d9f3e-6b55-4e2c-8d1f-3a7b2e9c8f01",
      "status": "INACTIVE"
    }
  ]'
```

The body is an array of 1 to 100 items. Each item takes `id` plus the fields described above.

## Response

Zod validates the entire body before saving. If any field is invalid, HTTP `400` is returned and no items are saved. When the body is valid, items are saved one after another. HTTP `200` only when every item is saved. If a later item hits a business error, HTTP is that item's status (`422` or `500`).

| Field | Description |
| - | - |
| `id` | The item `id`. `null` when it was missing or invalid. |
| `status` | `200` when saved. `422` for a duplicate `id`, an unknown provider or method, a method from another provider, an invalid `config`, or a create without provider and method. `500` for an unexpected failure. |
| `data` | The saved payment with secrets stripped from `config`, same shape as [Get payment](https://firespark.cloud/docs/integrations-api/payments/\[id]/get). Only when `status` is `200`. |
| `error` | Error message. Only when `status` is not `200`. |
| `details` | Error details for item-level failures, including invalid `config` field paths. |

```json Success theme={null}
{
  "data": [
    {
      "id": "3b1c8f2e-5a44-4d1b-9c0e-2f6a1d8b7e90",
      "status": 200,
      "data": {
        "id": "3b1c8f2e-5a44-4d1b-9c0e-2f6a1d8b7e90",
        "payment_provider_id": "6f1c8f2e-5a44-4d1b-9c0e-2f6a1d8b7e90",
        "payment_method_id": "7c1c8f2e-5a44-4d1b-9c0e-2f6a1d8b7e90",
        "config": { "public_key": "pk_test_123" },
        "status": "ACTIVE"
      }
    },
    {
      "id": "4c2d9f3e-6b55-4e2c-8d1f-3a7b2e9c8f01",
      "status": 422,
      "error": "Payment provider and method are required",
      "details": null
    }
  ]
}
```

```json Invalid fields theme={null}
{
  "error": "Invalid fields",
  "details": {
    "0.id": "Invalid UUID"
  }
}
```

## Error responses

| Status | Description |
| - | - |
| `400` | The body is not an array of 1 to 100 items, or any item has invalid fields. No items are saved. |
| `401` | Missing or invalid access token. |
| `403` | Token does not include the `payments:write` scope. |


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