# Bulk import payment methods

Import catalog payment methods in bulk.

Creates or attaches up to 500 catalog instruments in one request. Each row needs an iban, identifier, or code. Existing catalog keys are skipped. Counterparty identity follows the same cascade as invoice attach. Unknown instruments without a counterparty park on Unclassified.


- HTTP method: `POST`
- Path: `/api/v1/payment-methods/bulk`
- URL: `https://api.invunion.com/api/v1/payment-methods/bulk`
- Required scope: `payment_methods:write`
- HTML docs: https://www.invunion.com/knowledge-base/api/bulk-import-payment-methods/
- Markdown docs: https://www.invunion.com/knowledge-base/api/bulk-import-payment-methods.md



## Body parameters

| Name | Type | Required | Description | Allowed values | Example |
| --- | --- | --- | --- | --- | --- |
| `payment_methods` | array | required | Rows to import. Maximum 500. Each object needs iban, identifier, or code, plus optional counterparty identity fields. |  |  |
| `payment_methods.iban` | string, max 50 | recommended | IBAN. One of iban, identifier, or code is required. |  | `FR7630006000011234567890189` |
| `payment_methods.identifier` | string, max 120 | optional | Non-IBAN instrument key. |  | `carl@leonescars.fr` |
| `payment_methods.code` | string, max 50 | recommended | Existing PM-NNN code to look up. Code never creates a new instrument on its own. |  | `PM-001` |
| `payment_methods.name` | string, no maximum | optional | Display name. Defaults from the counterparty name or the instrument key. |  | `Leones Cars EUR` |
| `payment_methods.type` | string, no maximum | recommended | Instrument type. Default bank_account when an IBAN is present. | `bank_account`, `credit_card`, `paypal`, `wero`, `twint`, `crypto_wallet`, `other` |  |
| `payment_methods.bic` | string, max 11 | optional | BIC. |  | `BNPAFRPP` |
| `payment_methods.currency` | string, max 3 | optional | ISO 4217 currency. Default EUR. |  | `EUR` |
| `payment_methods.is_own_account` | boolean | optional | If true, import as a company account on an Internal counterparty. own_account is accepted as an alias. | `true`, `false` |  |
| `payment_methods.counterparty_id` | string, no maximum | recommended | Existing counterparty code (`account_code`). |  | `CPT-042` |
| `payment_methods.association_mode` | string, no maximum | recommended | exclusive (one owner) or shared (several counterparties). Default exclusive. | `exclusive`, `shared` |  |
| `payment_methods.account_code` | string, max 50 | optional | Counterparty account_code for identity lookup. |  | `CPT-042` |
| `payment_methods.counterparty_name` | string, no maximum | optional | Counterparty name used for identity lookup and, if needed, create. |  | `Leones Cars` |
| `payment_methods.external_reference` | string, max 255 | optional | Counterparty external reference. |  | `ERP-1842` |
| `payment_methods.vat_number` | string, max 50 | optional | Counterparty VAT number. |  | `FR12345678901` |
| `payment_methods.email` | string, no maximum | optional | Counterparty email. |  | `carl@leonescars.fr` |

## Errors

| Error | HTTP code | Description |
| --- | --- | --- |
| `Missing Bearer token` | `401` | The Authorization header is missing or is not a Bearer token. |
| `Invalid or revoked API key` | `401` | The API key is unknown, malformed, expired, or has been revoked. |
| `API key is missing scope payment_methods:write` | `403` | The key does not include payment_methods:write. A write scope does not imply the matching read scope. |
| `Too many requests, please try again later` | `429` | Wait and retry. The Retry-After header is the number of seconds to wait. |
| `Tenant ID required` | `400` | The authenticated credential is not bound to a tenant. |
| `payment_methods must be a non-empty array` | `400` | The body is missing payment_methods, or the array is empty. |
| `Maximum 500 payment methods per bulk import` | `400` | The array contains more than 500 rows. |
| `Internal server error` | `500` | Unexpected server error. The JSON body includes correlationId. Retry with backoff. |

## Request (curl)

```bash
curl --request POST \
  --url https://api.invunion.com/api/v1/payment-methods/bulk \
  --header 'accept: application/json' \
  --header 'authorization: Bearer uk_live_YOUR_API_KEY' \
  --header 'content-type: application/json' \
  --data '{
  "payment_methods": [
    {
      "name": "Leones Cars EUR",
      "iban": "FR7630006000011234567890189",
      "bic": "BNPAFRPP",
      "account_code": "CPT-042"
    },
    {
      "name": "Grove Street Garage",
      "iban": "FR1420041010050500013M02606",
      "account_code": "CPT-043"
    }
  ]
}'
```

## Request (Python)

```python
import requests

url = "https://api.invunion.com/api/v1/payment-methods/bulk"
headers = {
    "Accept": "application/json",
    "Authorization": "Bearer uk_live_YOUR_API_KEY",
    "Content-Type": "application/json",
}
payload = {
    "payment_methods": [
        {
            "name": "Leones Cars EUR",
            "iban": "FR7630006000011234567890189",
            "bic": "BNPAFRPP",
            "account_code": "CPT-042"
        },
        {
            "name": "Grove Street Garage",
            "iban": "FR1420041010050500013M02606",
            "account_code": "CPT-043"
        }
    ]
}
response = requests.post(url, json=payload, headers=headers)
print(response.json())
```

## Request (Ruby)

```ruby
require 'net/http'
require 'json'
require 'uri'

uri = URI("https://api.invunion.com/api/v1/payment-methods/bulk")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
request = Net::HTTP::Post.new(uri)
request['Accept'] = 'application/json'
request['Authorization'] = 'Bearer uk_live_YOUR_API_KEY'
request['Content-Type'] = 'application/json'
request.body = "{\n  \"payment_methods\": [\n    {\n      \"name\": \"Leones Cars EUR\",\n      \"iban\": \"FR7630006000011234567890189\",\n      \"bic\": \"BNPAFRPP\",\n      \"account_code\": \"CPT-042\"\n    },\n    {\n      \"name\": \"Grove Street Garage\",\n      \"iban\": \"FR1420041010050500013M02606\",\n      \"account_code\": \"CPT-043\"\n    }\n  ]\n}"
response = http.request(request)
puts response.body
```

## Request (JavaScript)

```javascript
const response = await fetch("https://api.invunion.com/api/v1/payment-methods/bulk", {
  method: "POST",
  headers: {
    "Accept": "application/json",
    "Authorization": "Bearer uk_live_YOUR_API_KEY",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
  "payment_methods": [
    {
      "name": "Leones Cars EUR",
      "iban": "FR7630006000011234567890189",
      "bic": "BNPAFRPP",
      "account_code": "CPT-042"
    },
    {
      "name": "Grove Street Garage",
      "iban": "FR1420041010050500013M02606",
      "account_code": "CPT-043"
    }
  ]
}),
});
const data = await response.json();
```

## Request (Go)

```go
package main

import (
	"bytes"
	"fmt"
	"io"
	"net/http"
)

func main() {
	payload := []byte(`{
  "payment_methods": [
    {
      "name": "Leones Cars EUR",
      "iban": "FR7630006000011234567890189",
      "bic": "BNPAFRPP",
      "account_code": "CPT-042"
    },
    {
      "name": "Grove Street Garage",
      "iban": "FR1420041010050500013M02606",
      "account_code": "CPT-043"
    }
  ]
}`)
	req, err := http.NewRequest("POST", "https://api.invunion.com/api/v1/payment-methods/bulk", bytes.NewBuffer(payload))
	if err != nil {
		panic(err)
	}
	req.Header.Set("Accept", "application/json")
	req.Header.Set("Authorization", "Bearer uk_live_YOUR_API_KEY")
	req.Header.Set("Content-Type", "application/json")
	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()
	body, _ := io.ReadAll(resp.Body)
	fmt.Println(string(body))
}
```

## Request (Node)

```javascript
const response = await fetch("https://api.invunion.com/api/v1/payment-methods/bulk", {
  method: "POST",
  headers: {
    "Accept": "application/json",
    "Authorization": "Bearer uk_live_YOUR_API_KEY",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
  "payment_methods": [
    {
      "name": "Leones Cars EUR",
      "iban": "FR7630006000011234567890189",
      "bic": "BNPAFRPP",
      "account_code": "CPT-042"
    },
    {
      "name": "Grove Street Garage",
      "iban": "FR1420041010050500013M02606",
      "account_code": "CPT-043"
    }
  ]
}),
});
console.log(await response.json());
```

## Success (201)

```json
{
  "success": true,
  "data": {
    "inserted": 1,
    "skipped": 0,
    "attached": 1,
    "counterparties_created": 0,
    "counterparties_linked": 2,
    "unclassified": 0,
    "own_accounts": 0,
    "total": 2,
    "errors": []
  },
  "message": "1 payment methods imported, 0 skipped"
}
```
