Every API here is available over the APIs.io API and to AI agents over MCP.
openapi: 3.2.0
info:
title: Benji Pays Merchant Payment Methods API
description: 'The Benji Pays Merchant API is a JSON over HTTPS API. All endpoints live under `/v2`. Errors follow RFC 7807 and are served as `application/problem+json`. This overview describes the cross-cutting behavior shared by every merchant endpoint. Endpoint-specific schemas live with each operation. ## Authentication
Merchant endpoints authenticate with an organization-scoped `x-api-key` header issued from the merchant app:
```
x-api-key:
```
The key is scoped to one organization and inherits the permissions of the login that created it. Failures return `401 Unauthorized` (missing/expired/invalid credentials) or `403 Forbidden` (insufficient mapping permission or organization lifecycle restrictions). ## Request and Correlation IDs
Two header pairs help with tracing:
| Header | Direction | Purpose |
| --- | --- | --- |
| `X-Request-ID` | request (optional) / response (always) | Unique identifier for one request. Generated as a UUID v4 when the client omits it. |
| `X-Correlation-ID` | request (optional) / response (always) | Identifier that flows across service boundaries for distributed tracing. Generated as a UUID v4 when omitted. |
Both IDs are echoed on success and included as `requestId` / `correlationId` extensions on `application/problem+json` error responses. These headers are auto-injected on every operation in this spec — do not redeclare them per route. ## Idempotency
POST, PATCH, and PUT endpoints accept an `Idempotency-Key` header to make retries safe. - Format: 1–255 characters, alphanumeric only (`[a-zA-Z0-9]+`). - Scope: keys are scoped per actor (no cross-tenant collisions). - Cache: the first response for a given key is cached for 24 hours. - Replay: a duplicate request with the same key and the same body returns the cached response with `X-Idempotency-Replayed: true` only after credentials were resolved by the global authenticate middleware (API key or Auth0 JWT signature check) before the idempotency cache lookup. - Conflict: same key with a different body returns `409 Conflict`. - In-flight: a second request with the same key while the first is still being processed returns `429 Too Many Requests` with `Retry-After` and problem `type` `https://api.benjipays.com/problems/idempotency-processing` (distinct from rate-limit `…/rate-limit-exceeded`). `Idempotency-Key` is auto-injected on every POST/PATCH/PUT operation in this spec — do not redeclare it per route. Routes that intentionally opt out set `x-bp-skip-idempotency: true`. The middleware fails open: if the cache layer is unavailable the request proceeds without idempotency protection. Most write routes treat the header as optional. Routes that require it set `x-bp-require-idempotency: true` and return `400 Bad Request` when it is missing — currently `POST /v2/transactions`, `POST /v2/transactions/prepayments`, and `POST /v2/transactions/{transactionId}/retry-accounting`. Those routes are also the exception to the fail-open rule above: when the cache layer is unavailable they return `503 Service Unavailable` with `Retry-After` and problem `type` `https://api.benjipays.com/problems/idempotency-unavailable`, and the request is not processed. Retry with the same key. The two charge routes (`POST /v2/transactions` and `POST /v2/transactions/prepayments`) also save the key on the charge. Recover a charge with `GET /v2/transactions?idempotencyKey={key}` (empty `data` when the key was never used). After the 24-hour replay window, the same key creates a new charge. ## Pagination
List endpoints use offset-based pagination with two query parameters:
| Parameter | Type | Default | Bounds |
| --- | --- | --- | --- |
| `limit` | integer | `20` | `1`–`1000` |
| `offset` | integer | `0` | `≥ 0` |
Some endpoints use different bounds (for example usage/billing and autoprocessing forecast). Check the per-operation schema.'
version: 2.0.0
contact:
name: Benji Pays API Support
email: benji@benjipays.com
servers:
- url: https://api.benjipays.com
description: Development server
security:
- ApiKeyAuth: []
tags:
- name: Payment Methods
description: Saved payment methods (profiles) for authenticated organizations
paths:
/v2/payment-methods:
get:
summary: List payment methods for an Organization
description: Returns paginated saved payment methods (profiles) for the organization associated with the authenticated API key. Filter by accounting `customerId` (QuickBooks Id, Xero ContactID, etc.) to list methods for one customer — the same pattern as the legacy `/api/profiles/list` route. Each item includes an internal Benji Pays profile `id`; use it with `GET /v2/payment-methods/{id}` to fetch a single resource (list rows do not include `mandate`).
tags:
- Payment Methods
security:
- ApiKeyAuth: []
parameters:
- $ref: '#/components/parameters/RequestIdHeader'
- $ref: '#/components/parameters/CorrelationIdHeader'
- in: query
name: search
schema:
description: Free-text search across payment method fields (customer name, masked card/account number, etc.).
type: string
maxLength: 200
description: Free-text search across payment method fields (customer name, masked card/account number, etc.).
- in: query
name: customerId
schema:
description: Filter to a single accounting customer ID (QuickBooks `Id`, Xero `ContactID`, Business Central `id`, QBD `ListID`).
type: string
maxLength: 200
description: Filter to a single accounting customer ID (QuickBooks `Id`, Xero `ContactID`, Business Central `id`, QBD `ListID`).
- in: query
name: gatewayId
schema:
description: Filter to a gateway store identifier (`gatewayId`).
type: string
maxLength: 200
description: Filter to a gateway store identifier (`gatewayId`).
- in: query
name: status
schema:
description: Filter by payment method status. Matches the merchant-app profiles table filters.
type: string
enum:
- enabled
- disabled
- error
description: Filter by payment method status. Matches the merchant-app profiles table filters.
- in: query
name: sort
schema:
description: 'Field to sort by (uses the same field names returned in the response). Accepted values: `customerName`, `createdDate`, `lastModifiedDate`, `lastDeclineDate`, `declineCount`, `autoPayPriority`, `gatewayId`, `gatewayProcessor`. Defaults to `customerName` (accounting customer display name denormalized on the profile).'
type: string
maxLength: 50
description: 'Field to sort by (uses the same field names returned in the response). Accepted values: `customerName`, `createdDate`, `lastModifiedDate`, `lastDeclineDate`, `declineCount`, `autoPayPriority`, `gatewayId`, `gatewayProcessor`. Defaults to `customerName` (accounting customer display name denormalized on the profile).'
- in: query
name: order
schema:
description: 'Sort direction. Accepted values: `asc` (default), `desc`.'
type: string
enum:
- asc
- desc
description: 'Sort direction. Accepted values: `asc` (default), `desc`.'
- in: query
name: limit
schema:
default: 20
type: integer
minimum: 1
maximum: 1000
- in: query
name: offset
schema:
default: 0
type: integer
minimum: 0
maximum: 9007199254740991
responses:
'200':
description: Paginated payment method list
content:
application/json:
schema:
$ref: '#/components/schemas/ListPaymentMethodsResponse'
'400':
description: Bad request — request validation failed (invalid query parameters; `type` `…/validation-error` with optional `errors[]`), and/or organization has no accounting integration configured.
content:
application/problem+json:
schema:
type: object
properties:
type:
type: string
title:
type: string
status:
type: number
detail:
type: string
instance:
type: string
required:
- type
- title
- status
- detail
additionalProperties: false
description: RFC 7807 Problem Details error response
'401':
description: Unauthorized
content:
application/problem+json:
schema:
type: object
properties:
type:
type: string
title:
type: string
status:
type: number
detail:
type: string
instance:
type: string
required:
- type
- title
- status
- detail
additionalProperties: false
description: RFC 7807 Problem Details error response
'403':
description: Forbidden — missing required OAuth scope (`organizations:payment-methods:read`), insufficient live mapping permission on the API key owner (e.g. `companyAdmin` or `manageProfiles`), and/or free trial ended without billing enabled. Scope, mapping, and billing state are independent gates; see response `detail`.
content:
application/problem+json:
schema:
type: object
properties:
type:
type: string
title:
type: string
status:
type: number
detail:
type: string
instance:
type: string
required:
- type
- title
- status
- detail
additionalProperties: false
description: RFC 7807 Problem Details error response
examples:
missingScope:
summary: Missing OAuth scope
value:
type: https://api.benjipays.com/problems/forbidden
title: Forbidden
status: 403
detail: 'Missing required scope: organizations:payment-methods:read'
instance: /v2/payment-methods
insufficientMappingPermission:
summary: Insufficient live mapping permission (API key owner)
value:
type: https://api.benjipays.com/problems/forbidden
title: Forbidden
status: 403
detail: Insufficient permission for this resource
instance: /v2/payment-methods
freeTrialOverNotPaying:
summary: Free trial ended without billing
value:
type: https://api.benjipays.com/problems/forbidden
title: Forbidden
status: 403
detail: Free trial has ended and billing is not enabled
instance: /v2/payment-methods
'404':
description: Organization not found
content:
application/problem+json:
schema:
type: object
properties:
type:
type: string
title:
type: string
status:
type: number
detail:
type: string
instance:
type: string
required:
- type
- title
- status
- detail
additionalProperties: false
description: RFC 7807 Problem Details error response
'429':
description: Too Many Requests
content:
application/problem+json:
schema:
type: object
properties:
type:
type: string
title:
type: string
status:
type: number
detail:
type: string
instance:
type: string
required:
- type
- title
- status
- detail
additionalProperties: false
description: RFC 7807 Problem Details error response
operationId: getV2PaymentMethods
x-operation-id-source: derived
/v2/payment-methods/{id}:
get:
summary: Get a payment method for an Organization
description: Returns a single saved payment method (profile) by its `id` (from `GET /v2/payment-methods`), scoped to the organization associated with the authenticated API key. Includes the nested `mandate` — the customer's recorded off-session billing authorization (e.g. Stripe accepted-at date, IP, and agreement text) — or `null` when no authorization was captured for this payment method. Use this to produce chargeback defense evidence for off-session charges.
tags:
- Payment Methods
security:
- ApiKeyAuth: []
parameters:
- $ref: '#/components/parameters/RequestIdHeader'
- $ref: '#/components/parameters/CorrelationIdHeader'
- in: path
name: id
schema:
type: string
minLength: 1
maxLength: 200
description: Payment method id (profile `_id`). Same id returned by GET /v2/payment-methods.
example: 66f1a2b3c4d5e6f789012345
required: true
description: Payment method id (profile `_id`). Same id returned by GET /v2/payment-methods.
responses:
'200':
description: Payment method, including its mandate (or null)
content:
application/json:
schema:
$ref: '#/components/schemas/PaymentMethodWithMandate'
'401':
description: Unauthorized
content:
application/problem+json:
schema:
type: object
properties:
type:
type: string
title:
type: string
status:
type: number
detail:
type: string
instance:
type: string
required:
- type
- title
- status
- detail
additionalProperties: false
description: RFC 7807 Problem Details error response
'403':
description: Forbidden — missing required OAuth scope (`organizations:payment-methods:read`), insufficient live mapping permission on the API key owner (e.g. `companyAdmin` or `manageProfiles`), and/or free trial ended without billing enabled. Scope, mapping, and billing state are independent gates; see response `detail`.
content:
application/problem+json:
schema:
type: object
properties:
type:
type: string
title:
type: string
status:
type: number
detail:
type: string
instance:
type: string
required:
- type
- title
- status
- detail
additionalProperties: false
description: RFC 7807 Problem Details error response
examples:
missingScope:
summary: Missing OAuth scope
value:
type: https://api.benjipays.com/problems/forbidden
title: Forbidden
status: 403
detail: 'Missing required scope: organizations:payment-methods:read'
instance: /v2/payment-methods/{id}
insufficientMappingPermission:
summary: Insufficient live mapping permission (API key owner)
value:
type: https://api.benjipays.com/problems/forbidden
title: Forbidden
status: 403
detail: Insufficient permission for this resource
instance: /v2/payment-methods/{id}
freeTrialOverNotPaying:
summary: Free trial ended without billing
value:
type: https://api.benjipays.com/problems/forbidden
title: Forbidden
status: 403
detail: Free trial has ended and billing is not enabled
instance: /v2/payment-methods/{id}
'404':
description: Organization not found, payment method not found, or payment method belongs to a different organization
content:
application/problem+json:
schema:
type: object
properties:
type:
type: string
title:
type: string
status:
type: number
detail:
type: string
instance:
type: string
required:
- type
- title
- status
- detail
additionalProperties: false
description: RFC 7807 Problem Details error response
'429':
description: Too Many Requests
content:
application/problem+json:
schema:
type: object
properties:
type:
type: string
title:
type: string
status:
type: number
detail:
type: string
instance:
type: string
required:
- type
- title
- status
- detail
additionalProperties: false
description: RFC 7807 Problem Details error response
operationId: getV2PaymentMethodsById
x-operation-id-source: derived
components:
schemas:
PaymentMethod:
type: object
properties:
id:
type: string
description: Payment method identifier (profile `_id`)
accountingCompanyId:
description: Accounting company ID
type: string
customerId:
description: Accounting system customer ID this payment method belongs to
type: string
accountingType:
description: Accounting platform type (e.g. quickbooks, xero)
type: string
gatewayProcessor:
description: Payment processor identifier (public key, e.g. `benjipayments`)
type: string
gatewayId:
description: Gateway store identifier
type: string
gatewayCustomerId:
description: Processor-specific customer ID
anyOf:
- type: string
- type: 'null'
vaultToken:
description: Processor payment-method token (e.g. Moneris data key, Stripe `pm_…` id), or `null` if none. Treat as sensitive.
anyOf:
- type: string
- type: 'null'
customerName:
description: Accounting customer display name (denormalized from the linked customer onto the profile)
type: string
maskedPan:
description: Masked card or bank account number
type: string
expiryMonth:
description: Card expiry month (CC only)
type: string
expiryYear:
description: Card expiry year (CC only)
type: string
cardBrand:
description: Card brand, e.g. Visa, Mastercard (CC only)
type: string
paymentType:
type: string
description: Payment type, defaults to "cc"
isDebitCard:
description: Whether the card is a debit card (CC only, defaults to false)
type: boolean
autoPayEnabled:
type: boolean
description: Whether autopay is enabled (enabled and not fuse-blown)
autoPayPriority:
description: Processing priority when multiple methods exist
type: number
benjiSurchargeEnabled:
type: boolean
description: Whether Benji surcharging is enabled (!surchargingDisabled)
note:
type: string
declineCount:
type: number
description: Number of declines, defaults to 0
lastDeclineDate:
anyOf:
- type: string
- type: 'null'
creatorIpAddress:
type: string
createdDate:
type: string
lastModifiedDate:
type: string
required:
- id
- paymentType
- autoPayEnabled
- benjiSurchargeEnabled
- declineCount
additionalProperties: false
description: Saved payment method for an accounting customer
ListPaymentMethodsResponse:
type: object
properties:
data:
type: array
items:
$ref: '#/components/schemas/PaymentMethod'
pagination:
type: object
properties:
total:
type: number
description: Total matching payment methods across all pages
limit:
type: number
offset:
type: number
hasMore:
type: boolean
nextOffset:
anyOf:
- type: number
- type: 'null'
prevOffset:
anyOf:
- type: number
- type: 'null'
required:
- total
- limit
- offset
- hasMore
- nextOffset
- prevOffset
additionalProperties: false
required:
- data
- pagination
additionalProperties: false
description: Paginated payment methods response
Mandate:
type: object
properties:
id:
type: string
description: Mandate identifier
acceptedAt:
anyOf:
- type: string
- type: 'null'
description: When the customer accepted off-session billing authorization (ISO-8601)
ip:
anyOf:
- type: string
- type: 'null'
description: IP address recorded at acceptance
type:
anyOf:
- type: string
- type: 'null'
description: 'Where the customer agreed: `web-app`, `payment-portal`, `customer-portal`, `api`, `billing-profile`, or `advanced-notification`.'
agreement:
anyOf:
- type: string
- type: 'null'
description: Authorization text the customer agreed to
loginName:
anyOf:
- type: string
- type: 'null'
description: Portal user name, if the mandate was accepted by a logged-in portal user
loginEmail:
anyOf:
- type: string
- type: 'null'
description: Portal user email, if the mandate was accepted by a logged-in portal user
required:
- id
- acceptedAt
- ip
- type
- agreement
- loginName
- loginEmail
additionalProperties: false
description: Off-session billing authorization mandate, e.g. for chargeback defense (Stripe accepted_at/IP)
PaymentMethodWithMandate:
type: object
properties:
id:
type: string
description: Payment method identifier (profile `_id`)
accountingCompanyId:
description: Accounting company ID
type: string
customerId:
description: Accounting system customer ID this payment method belongs to
type: string
accountingType:
description: Accounting platform type (e.g. quickbooks, xero)
type: string
gatewayProcessor:
description: Payment processor identifier (public key, e.g. `benjipayments`)
type: string
gatewayId:
description: Gateway store identifier
type: string
gatewayCustomerId:
description: Processor-specific customer ID
anyOf:
- type: string
- type: 'null'
vaultToken:
description: Processor payment-method token (e.g. Moneris data key, Stripe `pm_…` id), or `null` if none. Treat as sensitive.
anyOf:
- type: string
- type: 'null'
customerName:
description: Accounting customer display name (denormalized from the linked customer onto the profile)
type: string
maskedPan:
description: Masked card or bank account number
type: string
expiryMonth:
description: Card expiry month (CC only)
type: string
expiryYear:
description: Card expiry year (CC only)
type: string
cardBrand:
description: Card brand, e.g. Visa, Mastercard (CC only)
type: string
paymentType:
type: string
description: Payment type, defaults to "cc"
isDebitCard:
description: Whether the card is a debit card (CC only, defaults to false)
type: boolean
autoPayEnabled:
type: boolean
description: Whether autopay is enabled (enabled and not fuse-blown)
autoPayPriority:
description: Processing priority when multiple methods exist
type: number
benjiSurchargeEnabled:
type: boolean
description: Whether Benji surcharging is enabled (!surchargingDisabled)
note:
type: string
declineCount:
type: number
description: Number of declines, defaults to 0
lastDeclineDate:
anyOf:
- type: string
- type: 'null'
creatorIpAddress:
type: string
createdDate:
type: string
lastModifiedDate:
type: string
mandate:
anyOf:
- $ref: '#/components/schemas/Mandate'
- type: 'null'
description: Authorization mandate for this payment method, or null when none was captured
required:
- id
- paymentType
- autoPayEnabled
- benjiSurchargeEnabled
- declineCount
- mandate
additionalProperties: false
description: Saved payment method with its authorization mandate
parameters:
RequestIdHeader:
name: X-Request-ID
in: header
required: false
description: Optional client-supplied unique ID for one request. The server generates a UUID v4 if omitted and always echoes the value in the response.
schema:
type: string
format: uuid
CorrelationIdHeader:
name: X-Correlation-ID
in: header
required: false
description: Optional ID that flows across service boundaries for distributed tracing. The server generates a UUID v4 if omitted and always echoes the value in the response.
schema:
type: string
format: uuid
securitySchemes:
ApiKeyAuth:
type: apiKey
in: header
name: x-api-key
description: Organization-scoped API key. Send it in the x-api-key header. Available on organization endpoints only.
x-speakeasy-retries:
strategy: backoff
backoff:
initialInterval: 500
maxInterval: 60000
maxElapsedTime: 3600000
exponent: 1.5
statusCodes:
- 5XX
retryConnectionErrors: true
x-provenance:
method: searched
source: https://developer.benjipays.com/reference
harvested: '2026-11-02'
tool: harvest-readme-openapi.py
note: Assembled verbatim from the OpenAPI definition ReadMe embeds in each operation page of the provider's developer portal; paths and components merged by API title, nothing authored.
assembled_from:
- https://developer.benjipays.com/reference/delete_v2-customers-customerid-alert.md
- https://developer.benjipays.com/reference/delete_v2-customers-customerid-notes-noteid.md
- https://developer.benjipays.com/reference/get_v2-accounting-accounts.md
- https://developer.benjipays.com/reference/get_v2-autoprocessing-forecast.md
- https://developer.benjipays.com/reference/get_v2-customers-customerid-notes-noteid.md
- https://developer.benjipays.com/reference/get_v2-customers-customerid-notes.md
- https://developer.benjipays.com/reference/get_v2-customers-customerid.md
- https://developer.benjipays.com/reference/get_v2-customers.md
- https://developer.benjipays.com/reference/get_v2-emails-emailid.md
- https://developer.benjipays.com/reference/get_v2-emails.md
- https://developer.benjipays.com/reference/get_v2-gateways-capabilities.md
- https://developer.benjipays.com/reference/get_v2-gateways.md
- https://developer.benjipays.com/reference/get_v2-invoices-invoiceid-pdf.md
- https://developer.benjipays.com/reference/get_v2-invoices-invoiceid.md
- https://developer.benjipays.com/reference/get_v2-invoices.md
- https://developer.benjipays.com/reference/get_v2-notes-categories.md
- https://developer.benjipays.com/reference/get_v2-notes-statuses.md
- https://developer.benjipays.com/reference/get_v2-organization.md
- https://developer.benjipays.com/reference/get_v2-payment-method-requests-paymentmethodrequestid.md
- https://developer.benjipays.com/reference/get_v2-payment-method-requests.md
- https://developer.benjipays.com/reference/get_v2-payment-methods-id.md
- https://developer.benjipays.com/reference/get_v2-payment-methods.md
- https://developer.benjipays.com/reference/get_v2-settings.md
- https://developer.benjipays.com/reference/get_v2-transactions-transactionid-receipt.md
- https://developer.benjipays.com/reference/get_v2-transactions.md
- https://developer.benjipays.com/reference/get_v2-users.md
- https://developer.benjipays.com/reference/get_v2-whoami-1.md
- https://developer.benjipays.com/reference/patch_v2-customers-customerid-notes-noteid.md
- https://developer.benjipays.com/reference/patch_v2-customers-customerid.md
- https://developer.benjipays.com/reference/post_v2-customers-customerid-alert.md
- https://developer.benjipays.com/reference/post_v2-customers-customerid-notes-noteid-replies.md
- https://developer.benjipays.com/reference/post_v2-customers-customerid-notes-noteid-status.md
- https://developer.benjipays.com/reference/post_v2-customers-customerid-notes.md
- https://developer.benjipays.com/reference/post_v2-payment-links-applied-invoiceid.md
- https://developer.benjipays.com/reference/post_v2-payment-links-unapplied.md
- https://developer.benjipays.com/reference/post_v2-payment-method-requests.md
- https://developer.benjipays.com/reference/post_v2-transactions-prepayments.md
- https://developer.benjipays.com/reference/post_v2-transactions-transactionid-resend-receipt.md
- https://developer.benjipays.com/reference/post_v2-transactions-transactionid-retry-accounting.md
- https://developer.benjipays.com/reference/post_v2-transactions.md
merge:
pages: 40
deduped: 167
conflicts_kept_first: 0