Everything here is current behavior, not a roadmap. Each one is either a gap between the published description and what the gateway does, or a capability integrators regularly expect and the API does not have.
| Webhooks | No outbound notifications of any kind. Anything that happens after the response — settlement, an ACH return — is found by polling GET /v1/transactions |
| Idempotency | No Idempotency-Key header. Retrying a POST /v1/transactions that already succeeded creates a second transaction |
| 3-D Secure | No field carries a 3DS result, ECI value, or cardholder authentication cryptogram |
| Rate limiting | No 429 is returned today, and no rate limit is published |
| Delete | No endpoint deletes anything. Deactivate an integration with is_active: false |
| Users and roles | Not modeled on the public API. A client and its API key are the unit of access |
| Installments | Not offered. Recurring payments are, and are a different thing |
| Card Present | The gateway is Card-Not-Present only. Both entry_method values are CNP |
These return 400 and the published schema gives no hint of them.
| Field | What is rejected |
|---|---|
website on POST /v1/clients | Anything over 30 characters. No maximum is published |
Any email | Plus-addressing, and any top-level domain longer than four characters. ops+paradise@example.com and ops@acme.agency both fail |
admin_contact_details.phone | A separator after the country code — even though the shared Phone schema publishes +1-800-555-1234 as an example. Send +18005551234 |
| 52 string fields | An empty string, where the schema declares no minLength |
| Field | Behavior |
|---|---|
payment_method.card_type | Always UNKNOWN on a transaction response. The processor does not report it on the authorization. Read the transaction back from a reporting endpoint for the real value |
initiator | Comes back null on GET /v1/transactions/{id}, whatever you sent. Trust the create response |
return_code, return_reason | Omitted entirely, not null, when a transaction has not been returned. Code that reads the key without checking will throw on almost every transaction |
payment_method.payment_token | Carries the sentence Payment method could not be tokenized. when tokenization fails. Check for the PAYMENT_TOKEN- prefix before storing it |
payment_method.expiry | Null on capture, void and refund responses. Expiry is not echoed back on those |
A 200 is not proof a filter worked.
| Filter | Behavior |
|---|---|
type=PAYOUT | Accepted and then ignored. Returns unfiltered results rather than an error |
type=VOID | Returns a server error. A voided payment is reported as CANCEL — filter on that |
card_type=CREDIT or DEBIT | Quietly drops most rows, because card_type is usually UNKNOWN. Include UNKNOWN unless you specifically want determined rows |
card_type on GET /v1/batches/transactions | A different parameter from the one on GET /v1/transactions: narrower, no comma-separated list, and UNKNOWN returns 400 |
Real, and not yet reconciled. Documented so you are not surprised.
Paging and sorting differ by endpoint.
| Endpoint | Page size | Skip | Sort |
|---|---|---|---|
GET /v1/transactions | limit | offset | sort_by |
GET /v1/batches | take | skip | sort_column |
GET /v1/clients | Take | Skip | SortColumn |
That last row is PascalCase, alone in an otherwise snake_case API.
Processor names are spelled two ways. Tsys and Vericheck in a request body, TSYS and VERICHECK in a filter or a response. The body form is case-sensitive and sending the wrong one returns 400.
Transaction type has three vocabularies. SALE, AUTH and PAYOUT to create; the response and filter vocabulary adds INCREMENTAL_AUTH, REFUND, CANCEL and CAPTURE; and VOID or REFUND as the discriminator on a cancel body. You send VOID and you read CANCEL.
Four transaction endpoints declare a 404 they never return.
The description declares seven error_code values on its operations. Five more can reach you: INVALID_ACTION, REQUIRED_DATA_MISSING, AMOUNT_LIMIT_EXCEEDED, VELOCITY_LIMIT_EXCEEDED and INTEGRATION_CONFIG_ERROR.
A generated SDK's error enum is therefore not the whole list. Handle an unrecognized error_code by falling back on the HTTP status. See API response codes.