> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://api-docs.papertracc.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://api-docs.papertracc.com/_mcp/server.

# Create Payment

POST https://api.papertracc.com/v1/payments
Content-Type: application/json

Creates a payment and allocates it to one or more bills. An allocation can carry `wht_tax_id` and `wht_base` to withhold tax when paying the vendor. `amount` on the payment and on each allocation is the gross amount settled against the bills. The cash leaving the payment account is the gross amount less the total withholding, and the withheld amount is credited to withholding tax payable. When a bill carries an early-payment discount and the payment is dated on or before the discount deadline, an allocation that falls short of the bill's balance by no more than the discount settles the bill in full. The shortfall is reported as `discount_amount` on the allocation and credited to Other Income.

Requires the `can_create_payment` permission on the key owner's role.

**Keys:** secret key only.

Reference: https://api-docs.papertracc.com/core/payments/create-payment

## Authentication

- `Authorization` header (bearer token, required) — Bearer authentication of the form `Bearer <token>`, where token is your auth token.
- `identity` header (required) — The identity for the active workspace.

## Servers

- `https://api.papertracc.com/v1` (Production, default)
- `https://api.papertracc.com/rc-1` (Release Candidate 1)

## Request

### Body (application/json)

This endpoint expects an object.

- `amount` (string, required)
- `account_id` (string, required)
- `allocations` (list of PaymentsPostRequestBodyContentApplicationJsonSchemaAllocationsItems, required)
- `payment_date` (datetime, required)
- `staff_id` (string, optional)
- `vendor_id` (string, optional)
- `exchange_rate` (string, optional)
- `payment_method` (string, optional)
- `destination_account` (PaymentsPostRequestBodyContentApplicationJsonSchemaDestinationAccount, optional) — Passed through opaquely by the API; structure is not validated at this layer.

## Response

### 201

Created

- `data` (PaymentsPostResponsesContentApplicationJsonSchemaData, required)
- `status` (boolean, required)
- `message` (string, required)

## Errors

### 401 Unauthorized Error

The API key is missing or invalid, the key owner is no longer an active member of the organisation, or the key owner is not a member of the workspace in the `identity` header.

- `status` (boolean, required)
- `message` (string, required)
- `error_code` (enum, optional) — Machine-readable reason. Present on 402 and 403 responses.
  - Allowed values: `PERMISSION_DENIED`, `SERVICE_DISABLED`, `OPEN_API_NOT_ENABLED`
- `permission` (string, optional) — The role permission the request needs. Set when `error_code` is `PERMISSION_DENIED`.
- `service` (string, optional) — The workspace service that is turned off. Set when `error_code` is `SERVICE_DISABLED`.

### 402 Payment Required Error

The workspace's subscription plan does not include the Open API.

- `status` (boolean, required)
- `message` (string, required)
- `error_code` (enum, optional) — Machine-readable reason. Present on 402 and 403 responses.
  - Allowed values: `PERMISSION_DENIED`, `SERVICE_DISABLED`, `OPEN_API_NOT_ENABLED`
- `permission` (string, optional) — The role permission the request needs. Set when `error_code` is `PERMISSION_DENIED`.
- `service` (string, optional) — The workspace service that is turned off. Set when `error_code` is `SERVICE_DISABLED`.

### 403 Forbidden Error

Either the key owner's role does not include the permission this endpoint needs (`PERMISSION_DENIED`), or the service this endpoint belongs to is turned off for the workspace (`SERVICE_DISABLED`).

- `status` (boolean, required)
- `message` (string, required)
- `error_code` (enum, optional) — Machine-readable reason. Present on 402 and 403 responses.
  - Allowed values: `PERMISSION_DENIED`, `SERVICE_DISABLED`, `OPEN_API_NOT_ENABLED`
- `permission` (string, optional) — The role permission the request needs. Set when `error_code` is `PERMISSION_DENIED`.
- `service` (string, optional) — The workspace service that is turned off. Set when `error_code` is `SERVICE_DISABLED`.

## Types

### PaymentsPostRequestBodyContentApplicationJsonSchemaAllocationsItems

- `amount` (string, required)
- `bill_id` (string, required)
- `wht_tax_id` (string, optional) — A withholding tax profile (kind WHT, active, deducted on PAYMENT) to apply to this allocation. The allocation still settles the bill at the full `amount`. The vendor is owed the amount less the withholding, and the withheld amount is posted to the profile's withholding tax payable account.
- `wht_base` (double, optional) — The amount the withholding rate applies to. Cannot exceed `amount`. When omitted it follows the profile's `withholding_basis`: the VAT-exclusive share of `amount` for `EXCL_VAT`, or `amount` itself for `INCL_VAT`. Only used with `wht_tax_id`.

### PaymentsPostRequestBodyContentApplicationJsonSchemaDestinationAccount

Passed through opaquely by the API; structure is not validated at this layer.

- `bank` (string, required)
- `account_number` (string, required)

### PaymentsPostResponsesContentApplicationJsonSchemaData

- `id` (string, required)
- `type` (string, required)
- `amount` (string, required)
- `status` (string, required)
- `vendor` (PaymentsPostResponsesContentApplicationJsonSchemaDataVendor, required)
- `documents` (list of any, required)
- `vendor_id` (string, required)
- `account_id` (string, required)
- `created_at` (datetime, required)
- `project_id` (string, required)
- `allocations` (list of PaymentsPostResponsesContentApplicationJsonSchemaDataAllocationsItems, required)
- `payment_date` (datetime, required)
- `currency_code` (string, required)
- `exchange_rate` (string, required)
- `journal_status` (string, required)
- `payment_method` (string, required)
- `journal_entry_id` (string, required)
- `payment_reference` (string, required)
- `destination_account` (PaymentsPostResponsesContentApplicationJsonSchemaDataDestinationAccount, required)
- `staff` (any, optional)
- `staff_id` (any, optional)

### PaymentsPostResponsesContentApplicationJsonSchemaDataVendor

- `id` (string, required)
- `display_name` (string, required)

### PaymentsPostResponsesContentApplicationJsonSchemaDataAllocationsItems

- `id` (string, required)
- `amount` (string, required)
- `bill_id` (string, required)
- `payment_id` (string, required)
- `bill_reference` (string, required)
- `payment_status` (enum, optional) — How far the document has been settled, derived from amount and total_paid. Independent of status, which tracks the document workflow - a sent invoice that is part paid stays SENT with a payment_status of PARTIAL.
  - Allowed values: `UNPAID`, `PARTIAL`, `PAID`
- `wht_tax_id` (string, optional, nullable) — The withholding tax profile applied to this allocation, or null.
- `wht_rate` (string, optional) — The withholding rate applied, as a percentage.
- `wht_base` (string, optional) — The amount the withholding rate was applied to.
- `wht_amount` (string, optional) — The tax withheld on this allocation. 0.00 when none was withheld.
- `discount_amount` (string, optional) — The early-payment discount taken on this allocation. 0.00 when none was taken. It is included in `amount`.

### PaymentsPostResponsesContentApplicationJsonSchemaDataDestinationAccount

- `bank` (string, required)
- `account_number` (string, required)

## Examples

**Request**

```json
{
  "amount": "250000.00",
  "account_id": "d037d299-3029-4dc7-8e72-172f80f23c4f",
  "allocations": [
    {
      "amount": "250000.00",
      "bill_id": "45c6e26d-e132-4548-8e2e-5bfc467cf94a"
    }
  ],
  "payment_date": "2026-06-18T10:00:00.000Z",
  "staff_id": "7d2c9c72-392c-4f8d-b3f1-c1fef2c2d501",
  "vendor_id": "0cb2d1a5-2f50-43a1-8c3f-df06f998ef51",
  "exchange_rate": "1.00",
  "payment_method": "BANK_TRANSFER",
  "destination_account": {
    "bank": "Spruce Bank",
    "account_number": "1234567890"
  }
}
```

**Response**

```json
{
  "data": {
    "id": "59ad58e5-1571-4ce5-a140-6e7e33beb47c",
    "type": "BILL_PAYMENT",
    "amount": "250000.00",
    "status": "POSTED",
    "vendor": {
      "id": "0cb2d1a5-2f50-43a1-8c3f-df06f998ef51",
      "display_name": "Global Softworks"
    },
    "documents": [],
    "vendor_id": "0cb2d1a5-2f50-43a1-8c3f-df06f998ef51",
    "account_id": "d037d299-3029-4dc7-8e72-172f80f23c4f",
    "created_at": "2026-06-18T10:00:00Z",
    "project_id": "spruce-demo",
    "allocations": [
      {
        "id": "5c998a23-a6fc-4c2e-8e22-7f90ad81ce0a",
        "amount": "250000.00",
        "bill_id": "45c6e26d-e132-4548-8e2e-5bfc467cf94a",
        "payment_id": "59ad58e5-1571-4ce5-a140-6e7e33beb47c",
        "bill_reference": "BILL-0001",
        "wht_tax_id": null,
        "wht_rate": "0.00",
        "wht_base": "0.00",
        "wht_amount": "0.00",
        "discount_amount": "0.00"
      }
    ],
    "payment_date": "2026-06-18T10:00:00Z",
    "currency_code": "NGN",
    "exchange_rate": "1.00",
    "journal_status": "POSTED",
    "payment_method": "BANK_TRANSFER",
    "journal_entry_id": "JE-0003",
    "payment_reference": "PAY-0001",
    "destination_account": {
      "bank": "Spruce Bank",
      "account_number": "1234567890"
    }
  },
  "status": true,
  "message": "Successfully created payment"
}
```

**SDK Code**

```python Payments_Create Payment_example
import requests

url = "https://api.papertracc.com/v1/payments"

payload = {
    "amount": "250000.00",
    "account_id": "d037d299-3029-4dc7-8e72-172f80f23c4f",
    "allocations": [
        {
            "amount": "250000.00",
            "bill_id": "45c6e26d-e132-4548-8e2e-5bfc467cf94a"
        }
    ],
    "payment_date": "2026-06-18T10:00:00.000Z",
    "staff_id": "7d2c9c72-392c-4f8d-b3f1-c1fef2c2d501",
    "vendor_id": "0cb2d1a5-2f50-43a1-8c3f-df06f998ef51",
    "exchange_rate": "1.00",
    "payment_method": "BANK_TRANSFER",
    "destination_account": {
        "bank": "Spruce Bank",
        "account_number": "1234567890"
    }
}
headers = {
    "Authorization": "Bearer <apiKey>",
    "Content-Type": "application/json"
}

response = requests.post(url, json=payload, headers=headers)

print(response.json())
```

```javascript Payments_Create Payment_example
const url = 'https://api.papertracc.com/v1/payments';
const options = {
  method: 'POST',
  headers: {Authorization: 'Bearer <apiKey>', 'Content-Type': 'application/json'},
  body: '{"amount":"250000.00","account_id":"d037d299-3029-4dc7-8e72-172f80f23c4f","allocations":[{"amount":"250000.00","bill_id":"45c6e26d-e132-4548-8e2e-5bfc467cf94a"}],"payment_date":"2026-06-18T10:00:00.000Z","staff_id":"7d2c9c72-392c-4f8d-b3f1-c1fef2c2d501","vendor_id":"0cb2d1a5-2f50-43a1-8c3f-df06f998ef51","exchange_rate":"1.00","payment_method":"BANK_TRANSFER","destination_account":{"bank":"Spruce Bank","account_number":"1234567890"}}'
};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

```go Payments_Create Payment_example
package main

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

func main() {

	url := "https://api.papertracc.com/v1/payments"

	payload := strings.NewReader("{\n  \"amount\": \"250000.00\",\n  \"account_id\": \"d037d299-3029-4dc7-8e72-172f80f23c4f\",\n  \"allocations\": [\n    {\n      \"amount\": \"250000.00\",\n      \"bill_id\": \"45c6e26d-e132-4548-8e2e-5bfc467cf94a\"\n    }\n  ],\n  \"payment_date\": \"2026-06-18T10:00:00.000Z\",\n  \"staff_id\": \"7d2c9c72-392c-4f8d-b3f1-c1fef2c2d501\",\n  \"vendor_id\": \"0cb2d1a5-2f50-43a1-8c3f-df06f998ef51\",\n  \"exchange_rate\": \"1.00\",\n  \"payment_method\": \"BANK_TRANSFER\",\n  \"destination_account\": {\n    \"bank\": \"Spruce Bank\",\n    \"account_number\": \"1234567890\"\n  }\n}")

	req, _ := http.NewRequest("POST", url, payload)

	req.Header.Add("Authorization", "Bearer <apiKey>")
	req.Header.Add("Content-Type", "application/json")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

```ruby Payments_Create Payment_example
require 'uri'
require 'net/http'

url = URI("https://api.papertracc.com/v1/payments")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <apiKey>'
request["Content-Type"] = 'application/json'
request.body = "{\n  \"amount\": \"250000.00\",\n  \"account_id\": \"d037d299-3029-4dc7-8e72-172f80f23c4f\",\n  \"allocations\": [\n    {\n      \"amount\": \"250000.00\",\n      \"bill_id\": \"45c6e26d-e132-4548-8e2e-5bfc467cf94a\"\n    }\n  ],\n  \"payment_date\": \"2026-06-18T10:00:00.000Z\",\n  \"staff_id\": \"7d2c9c72-392c-4f8d-b3f1-c1fef2c2d501\",\n  \"vendor_id\": \"0cb2d1a5-2f50-43a1-8c3f-df06f998ef51\",\n  \"exchange_rate\": \"1.00\",\n  \"payment_method\": \"BANK_TRANSFER\",\n  \"destination_account\": {\n    \"bank\": \"Spruce Bank\",\n    \"account_number\": \"1234567890\"\n  }\n}"

response = http.request(request)
puts response.read_body
```

```java Payments_Create Payment_example
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.post("https://api.papertracc.com/v1/payments")
  .header("Authorization", "Bearer <apiKey>")
  .header("Content-Type", "application/json")
  .body("{\n  \"amount\": \"250000.00\",\n  \"account_id\": \"d037d299-3029-4dc7-8e72-172f80f23c4f\",\n  \"allocations\": [\n    {\n      \"amount\": \"250000.00\",\n      \"bill_id\": \"45c6e26d-e132-4548-8e2e-5bfc467cf94a\"\n    }\n  ],\n  \"payment_date\": \"2026-06-18T10:00:00.000Z\",\n  \"staff_id\": \"7d2c9c72-392c-4f8d-b3f1-c1fef2c2d501\",\n  \"vendor_id\": \"0cb2d1a5-2f50-43a1-8c3f-df06f998ef51\",\n  \"exchange_rate\": \"1.00\",\n  \"payment_method\": \"BANK_TRANSFER\",\n  \"destination_account\": {\n    \"bank\": \"Spruce Bank\",\n    \"account_number\": \"1234567890\"\n  }\n}")
  .asString();
```

```php Payments_Create Payment_example
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('POST', 'https://api.papertracc.com/v1/payments', [
  'body' => '{
  "amount": "250000.00",
  "account_id": "d037d299-3029-4dc7-8e72-172f80f23c4f",
  "allocations": [
    {
      "amount": "250000.00",
      "bill_id": "45c6e26d-e132-4548-8e2e-5bfc467cf94a"
    }
  ],
  "payment_date": "2026-06-18T10:00:00.000Z",
  "staff_id": "7d2c9c72-392c-4f8d-b3f1-c1fef2c2d501",
  "vendor_id": "0cb2d1a5-2f50-43a1-8c3f-df06f998ef51",
  "exchange_rate": "1.00",
  "payment_method": "BANK_TRANSFER",
  "destination_account": {
    "bank": "Spruce Bank",
    "account_number": "1234567890"
  }
}',
  'headers' => [
    'Authorization' => 'Bearer <apiKey>',
    'Content-Type' => 'application/json',
  ],
]);

echo $response->getBody();
```

```csharp Payments_Create Payment_example
using RestSharp;

var client = new RestClient("https://api.papertracc.com/v1/payments");
var request = new RestRequest(Method.POST);
request.AddHeader("Authorization", "Bearer <apiKey>");
request.AddHeader("Content-Type", "application/json");
request.AddParameter("application/json", "{\n  \"amount\": \"250000.00\",\n  \"account_id\": \"d037d299-3029-4dc7-8e72-172f80f23c4f\",\n  \"allocations\": [\n    {\n      \"amount\": \"250000.00\",\n      \"bill_id\": \"45c6e26d-e132-4548-8e2e-5bfc467cf94a\"\n    }\n  ],\n  \"payment_date\": \"2026-06-18T10:00:00.000Z\",\n  \"staff_id\": \"7d2c9c72-392c-4f8d-b3f1-c1fef2c2d501\",\n  \"vendor_id\": \"0cb2d1a5-2f50-43a1-8c3f-df06f998ef51\",\n  \"exchange_rate\": \"1.00\",\n  \"payment_method\": \"BANK_TRANSFER\",\n  \"destination_account\": {\n    \"bank\": \"Spruce Bank\",\n    \"account_number\": \"1234567890\"\n  }\n}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```

```swift Payments_Create Payment_example
import Foundation

let headers = [
  "Authorization": "Bearer <apiKey>",
  "Content-Type": "application/json"
]
let parameters = [
  "amount": "250000.00",
  "account_id": "d037d299-3029-4dc7-8e72-172f80f23c4f",
  "allocations": [
    [
      "amount": "250000.00",
      "bill_id": "45c6e26d-e132-4548-8e2e-5bfc467cf94a"
    ]
  ],
  "payment_date": "2026-06-18T10:00:00.000Z",
  "staff_id": "7d2c9c72-392c-4f8d-b3f1-c1fef2c2d501",
  "vendor_id": "0cb2d1a5-2f50-43a1-8c3f-df06f998ef51",
  "exchange_rate": "1.00",
  "payment_method": "BANK_TRANSFER",
  "destination_account": [
    "bank": "Spruce Bank",
    "account_number": "1234567890"
  ]
] as [String : Any]

let postData = JSONSerialization.data(withJSONObject: parameters, options: [])

let request = NSMutableURLRequest(url: NSURL(string: "https://api.papertracc.com/v1/payments")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```