Changelog
Dated entries for material changes to the FlexFactor public API, OpenAPI schema, webhook events, payload fields, and response statuses.
This changelog records material changes to the FlexFactor public API surface. Use it to detect drift between an integration built against an earlier snapshot of these docs and the current contract.
What counts as a material change:
- An endpoint added, removed, or marked deprecated
- A request or response field added, removed, renamed, or having its required-ness or type changed
- A response status enum or webhook event added or removed
- A retry / idempotency / rate-limit rule change
- An Optimization Rank change for any documented field
What does not count (no entry required):
- Wording or formatting changes that preserve meaning
- Example-payload edits that do not change the contract
- Brand or domain renames (covered by a single rollup entry)
Entries are most-recent-first. Each entry names the affected pages and the OpenAPI version when relevant.
2026-11-02
A review pass compared every guide page with the regenerated OpenAPI reference. The changes below record the places where the pages said something the schema does not.
| Type | Area | Change | Pages |
|---|---|---|---|
| Removed | /v1/transmit request | threeDsecure is removed from the /transmit field table and examples. The TransmitRequest schema has no such object. /v1/evaluate still accepts threeDsecure. | transmit.md |
| Changed | /v1/evaluate request | The ACH paymentMethod.value fields are camelCase: accountType, accountNumber, routingNumber, and accountHolderType. The page previously showed them in PascalCase. | evaluate.md |
| Clarified | /v1/orders/{id}/cancel, /v1/orders/{id}/void, and the external- variants | The envelope status field is not meaningful on these endpoints and is null in current responses; read success. A 500 returns the envelope with success: false and responseMessage, for example Failed to cancel order. On /void, the behavior of a request without amount is not documented; send amount on every request. | cancel.md, void.md, workflows.md §3.5, certification-guide |
| Added | HTTP status codes | Each endpoint page now carries an HTTP status code table: new on /evaluate, /transmit, /tokenize, GET /v1/orders, and GET /v1/orders/{id}; a 401 row is added on /capture and /refund. The OpenAPI reference declares a 400 validation response on /evaluate. | evaluate.md, transmit.md, tokenize.md, get-orders.md, orders-id.md, capture.md, refund.md, API reference |
| Clarified | /v1/tokenize | The mid and environment query parameters are optional in the schema, but they authenticate the call. A request without a valid mid and environment returns 401. TOKENIZE-04 now expects 401 only. | tokenize.md, certification-authentication-and-card-data |
2026-10-30
The OpenAPI reference was regenerated from the backend export of 2026-10-28. The published schema now declares only the fields the backend declares as required; the guide pages were aligned to it, and the Optimization Rank Required tier now marks the fields FlexFactor needs to evaluate an order even though the schema does not enforce them.
| Type | Area | Change | Pages |
|---|---|---|---|
| Changed | /v1/evaluate request | The attempt counter field is attemptNumber. The previously documented attemptCount was not read by the API. Send attemptNumber with the same meaning: 1 for the original attempt, 2 for the first retry, and so on. | evaluate.md, preevaluate.md, payload-examples.md, workflows.md, certification-reference, Evaluate API recipe |
| Changed | /v1/evaluate, /v1/capture request | idempotencyKey is optional and recommended, not required. A request without a key is processed without replay protection. A key that is not a GUID returns 400. Replay and 409 conflict behavior are unchanged. | evaluate.md, capture.md, workflows.md §3.4, certification-idempotency-and-errors |
| Clarified | GET /v1/orders, GET /v1/orders/{id} | status is a lowercase string: draft, onhold, cancelled, problem, processing, capturerequired, returned, completed, disputed. The guide pages previously showed the numeric codes. statusName is deprecated on both endpoints: on GET /v1/orders read status, and on GET /v1/orders/{id} read the new state field (Processing, Cancelled, CaptureRequired, Completed). GET /v1/orders/{id} also returns currency (ISO code), siteId, and a paymentMethod object with token and last4; its currencyCode is the numeric ISO code; its activity items carry bin, last4, isExternal, and discountAmount; and it no longer returns isCancelable. GET /v1/orders rows do not carry state, and they keep the string currencyCode and isCancelable. | orders-id.md, get-orders.md, evaluate.md, workflows.md §3.5, cancel.md, void.md, refund.md |
| Changed | /v1/evaluate, /v1/transmit request | The field tables' Required? column is renamed API validation and now mirrors what the API schema enforces, which on these two endpoints is no field; the Optimization Rank column carries what FlexFactor needs. On /evaluate, the 3DS object is spelled threeDsecure (see the 2026-11-02 entry for /transmit). Wallet payer.paymentMethods entries use type, value, and billingInformation. orderItems[].quantity is an integer. New optional fields: caller, extraData, userDefinedFields, fullName on billing and shipping information, customerIp on /transmit, and token on the /transmit payment method. | evaluate.md, transmit.md, payload-examples.md, preevaluate.md |
| Added | /v1/evaluate response | metadata: optional key/value entries about the outcome, for example SchemeTransactionId on APPROVED and CAPTUREREQUIRED when the account has opted in. /v1/transmit returns the standard envelope plus transmitId. | evaluate.md, transmit.md |
| Changed | /v1/tokenize | The request is camelCase: paymentMethod.creditCard with number, month, year required and firstName, lastName, verificationValue optional; email, senseKey, and the new metadata map are optional. The mid and environment query parameters are optional in the schema. The response is the standard envelope plus id, the FlexFactor token. | tokenize.md, /tokenize reference |
| Clarified | /v1/orders/{id}/cancel, external-cancel | The response is the full void envelope (success, result, status, statusCode, errors, customProperties, responseCode, responseMessage). | cancel.md |
| Added | /v1/orders/{id}/refund request | Optional isConsumerRequestedRefund, transactionId, and supportedGatewayId are documented. A request with neither amount nor amountToRefund fails validation with 400. | refund.md |
| Clarified | Error responses | A 404 carries a problem-details body on capture, cancel, void, and refund. | capture.md, cancel.md, void.md, refund.md, errors.md |
| Changed | GET /v1/merchants | status is ACTIVE or INACTIVE. bankAccountInformation is no longer returned. New externalMerchantIdentifier and partnerResellerReference. Sites carry location, useLocationDescriptor, and state; descriptorCity is deprecated in favour of location.city. | get-merchant.md, list-of-merchants.md |
| Changed | Certification guide | IDEMPOTENCY-04 now expects an omitted key to be accepted and a non-GUID key to return 400. CAPTURE-04 (missing key returns 400) is removed; the guide still requires the key on every capture. IDEMPOTENCY-06 reads the string status; IDEMPOTENCY-07 reads status and state. IDEMPOTENCY-08, CAPTURE-03, CANCEL-07, and VOID-09 expect a problem-details 404 body. CANCEL-01 and CANCEL-03 read the void envelope. TOKENIZE-01 to 03 use the camelCase request and the id token. Every case that cited a numeric order status now cites the string. Payloads send attemptNumber and threeDsecure. The test-case workbook is regenerated. | certification-guide, certification-idempotency-and-errors, certification-capture-cancel-refund, certification-authentication-and-card-data, certification-reference |
| Changed | OpenAPI reference | Regenerated from the backend export. /v1/outcome is removed from the reference. The {external-order-id} path parameter, GET /v1/orders, the token response schema, the documented 400, 409, and 503 responses, and the error-item shape are restored on top of the export. | API reference |
2026-10-28
| Type | Area | Change | Pages |
|---|---|---|---|
| Added | /v1/orders/{id}/void | New endpoint that voids all or part of a pending order before capture. The body takes an optional amount in cents, an optional idempotencyKey, and optional mid and transactionId. An amount equal to the order amount cancels the order (status cancelled, order.cancelled); a lower amount reduces the order and leaves the remainder open for /capture. Eligible orders are the same as /cancel. Partial voids must be enabled per account. OpenAPI: new path plus VoidRequest and VoidResult schemas. /cancel and /external-cancel are unchanged. | void.md, orders index, cancel.md, workflows.md §2.6, /void reference |
| Added | /v1/orders/{external-order-id}/external-void | New endpoint that voids all or part of a pending order identified by your own external order ID (the orderId you sent to /evaluate). Same body, eligibility, full and partial void behavior, and response as /void. OpenAPI: new path using the VoidRequest and VoidResult schemas. | void.md, orders index, workflows.md §2.6, §3.4, /external-void reference |
| Added | /v1/orders/{id}/refund request | New amount field: the refund amount in cents, matching /capture and /void. Send amount or amountToRefund, not both. | refund.md, workflows.md §2.7, webhooks, /refund reference |
| Deprecated | /v1/orders/{id}/refund request | amountToRefund (dollars) is deprecated and no longer required. It is still accepted; use amount in new integrations. The read-only amountToRefundInCents is removed from the documented request schema. GET /v1/orders/{id} still reports refundsAmount in dollars. | refund.md, /refund reference |
| Changed | Certification guide | Refund cases REFUND-01, 03, 05, and 06 now send amount in cents. New REFUND-09 covers the deprecated amountToRefund field and is required only for integrations that send it. New VOID-10 covers external-void. Appendix A.4 and C.4 updated. The test-case workbook is regenerated. | certification-capture-cancel-refund, certification-reference, certification-guide |
| Added | Certification guide | New VOID scope profile and Section 9.2 Void (VOID-01 to VOID-09). Section 9 renamed "Cancel and void"; the existing cancel cases are now 9.1 Cancel with unchanged IDs. Appendix A.5 void request and an Appendix C.4 row added. The test-case workbook is regenerated. | certification-guide, certification-capture-cancel-refund, certification-reference |
2026-10-20
| Type | Area | Change | Pages |
|---|---|---|---|
| Clarified | Response envelope (all endpoints) | One definition of the shared envelope (success, result, status, statusCode, errors, customProperties) and of how the HTTP status code, success, result, and status relate. HTTP 200 means the request reached FlexFactor; the outcome is in status. result is populated on /evaluate only (Success | Failed, mixed case) and is null on /capture, /refund, and /cancel. statusCode is never populated on any payment or order endpoint. errors items are serialized positionally (item1 message, item2 key, item3 code, item4 friendly flag). Per-endpoint status vocabularies tabulated. Docs-only — the API has always behaved this way. | workflows.md §3.5, evaluate.md, capture.md, refund.md, errors.md, evaluate-api.md |
| Clarified | /v1/evaluate | result values corrected to Success | Failed (previously shown as SUCCESS | FAILED). Failed is returned only when the evaluation did not complete (evaluation timeout, concurrent evaluation of the same order, unexpected error), with status: DECLINED as a fallback and success: false, still under HTTP 200. Request-validation failures return 400. Docs-only correction. | evaluate.md, workflows.md §2.1, §3.5 |
| Changed | /v1/capture response | status is SUCCESS | FAILED (the capture outcome), not APPROVED | DECLINED as previously documented. result is always null. success stays true on a processor capture failure, so integrations must key on status. HTTP status table added: 400 validation (capture not enabled, wrong order state, amount or currency mismatch), 404 empty (unknown order), 500 plain text Capture call failed, idempotency 409 / 500 / 503. Docs-only correction — the API has always behaved this way. | capture.md, workflows.md §2.2, §2.4, §3.5, errors.md |
| Clarified | Capture window expiry | An authorization not captured within the capture window (5 minutes by default, measured from the order's last update, adjustable per merchant) resolves to Cancelled (status 2) and fires order.expired — on CIT authorize, MIT authorize, and Sync MIT alike. Previously described only as "it will void". | capture.md, evaluate.md, webhooks-1.md, workflows.md §2.2, §3.3, §3.5 |
| Added | Transaction state model | A consolidated table mapping each order state across the synchronous /evaluate and /capture response, the GET /orders numeric status / statusName, and the webhook that announces it, with pending / terminal flags and the integrator action for each. | workflows.md §3.5, orders-id.md, webhooks-1.md |
| Clarified | Webhooks | order.completed fires on every flow, including synchronous CIT approvals and successful captures, delivered asynchronously after the API response and only when the order status changes and the endpoint subscribes to the event. order.expired also covers uncaptured authorizations. | webhooks-1.md |
| Changed | /v1/orders/{id}/cancel, /v1/orders/{external-order-id}/external-cancel | Response body documented as { "success": true, "responseMessage": null } (previously "empty"). A cancel against an order outside the cancellable states also returns HTTP 200 with success: true and leaves the order unchanged, so a 200 must be confirmed with GET /orders/{id} or order.cancelled. 404 returns an empty body; 500 returns { "success": false, "responseMessage": "Failed to cancel order" }; no webhook fires for a cancel that changed nothing. Cancellable states corrected: MIT orders in any state except Completed or Cancelled; CIT orders in Capturerequired or Onhold. Cancel always applies to the full order amount; there is no partial cancel, and the body accepts only the optional idempotencyKey. Docs-only — the API has always behaved this way. | cancel.md, workflows.md §2.6, §3.5 |
| Changed | GET /orders/{id} | isCancelable documented: true when the status is Draft, Onhold, or Processing; it does not reflect what /cancel accepts. refundsAmount is returned in dollars (previously documented as cents); example corrected. Existing fields in the OpenAPI OrdersQueryResponseDTO schema. | orders-id.md |
| Clarified | GET /orders/{id} Order status table | Corrected the "Returned by" column: Cancelled is a GET /orders status announced by order.cancelled or order.expired, not an /evaluate response; Approved and Declined are response values only; Completed pairs with order.completed. Docs-only correction. | orders-id.md |
| Clarified | Order status after a refund | A full or partial refund leaves the order at Completed (7) and increases refundsAmount; status 6 Returned is defined in the enum but is not assigned by a refund. Previously documented as moving to Returned. Docs-only correction. | evaluate.md, refund.md, orders-id.md, workflows.md §3.3, §3.5 |
| Clarified | /v1/orders/{id}/refund | The response table now documents status as the refund outcome (SUCCESS | FAILED), matching the response example; it previously read "success / fail". result and statusCode are never populated on this endpoint (always null); check success and status. Full and partial refunds documented as the same request: amountToRefund in dollars, below the captured amount for a partial refund, several partial refunds allowed, no currency field (the order currency applies); an amount above the remaining refundable balance fails validation with 400. Full-refund and partial-refund request examples and a failed-refund response example added. Docs-only correction. | refund.md |
| Added | /v1/orders/{id}/refund | responseCode, responseMessage, and transactionId documented on the refund response (transactionId is set on success only). Existing fields in the OpenAPI RefundResult schema, previously undocumented on the guide page. | refund.md |
| Clarified | /v1/orders/{id}/refund HTTP status codes | A failed refund normally returns HTTP 200 with status: FAILED and success: false — a processor decline carries responseCode / responseMessage; an unexpected failure carries REFUND_FAILED in errors. Validation errors and errors raised before the refund runs return 400; 409 / 500 / 503 follow the idempotency rules. Docs-only — the API has always behaved this way. | refund.md, workflows.md §3.5 |
| Clarified | Idempotency (/v1/orders/{id}/refund) | Same-key retry behavior differs by failure type: a processor-declined refund is not stored against the key, so the retry runs the refund again; an unexpected failure is stored and replayed without re-running the refund. Docs-only. | refund.md, workflows.md §3.4 |
2026-09-24
| Type | Area | Change | Pages |
|---|---|---|---|
| Changed | /v1/evaluate (async MIT) | expiryDateUtc is now optional on async MIT, as it already was on Sync MIT. When it is omitted, the default expiry configured for the merchant in FlexFactor applies; when it is sent, it is honored for that order. The rescue window remains up to 21 days from the original decline. | evaluate.md, workflows.md, payload-examples.md, webhooks-1.md |
2026-08-11
| Type | Area | Change | Pages |
|---|---|---|---|
| Clarified | /v1/evaluate (Sync MIT) | expiryDateUtc is optional on this flow and normally omitted. When it is omitted, the rescue window comes from portal configuration as a period expressed in hours from the timestamp the decline was received (async MIT uses expiryDateUtc, with a window of up to 21 days). A supplied value is honored on a direct API integration; on gateway-routed integrations the field is not conveyed and the portal-configured window applies. API behavior is unchanged. | workflows.md §2.5 |
| Clarified | /v1/capture, /v1/evaluate (Sync MIT) | Capture on this flow is conditional: a retry /evaluate against a CAPTUREREQUIRED order acts as the capture, and an explicit POST /v1/capture completes the order equally well — FlexFactor does not initiate the capture itself. If neither call reaches the order before the rescue window closes, the order is not captured. On gateway-routed integrations, the gateway's standard capture is relayed to FlexFactor as the capture for the order. Sync MIT capture behavior is now documented in full in §2.5. | workflows.md §2.5, capture.md, webhooks-1.md |
| Clarified | Sync MIT rescue window | The cutoff is hard — there is no grace period. A call arriving after the window closes returns DECLINED even when the order was rescued and awaiting capture, so an uncaptured rescue cannot be completed late. | workflows.md §2.5 |
| Clarified | Order status, order.expired | A Sync MIT order that is rescued but not captured resolves to Cancelled (status 2) and fires order.expired — the same responses, final order state, and webhook as an order that was never rescued. Whether order.capturerequired fired earlier for that order is the distinguishing signal, so Cancelled + order.expired does not on its own indicate that the rescue failed. | workflows.md §2.5, §3.3 |
| Clarified | Order status | Status 5 Capturerequired now documents that on Sync MIT a further /evaluate also completes the order, and that one of the two calls must arrive for the order to be captured. | workflows.md §3.3 |
| Added | Webhooks (Sync MIT) | Recommended handling for Sync MIT: subscribe to order.capturerequired and complete the order on receipt rather than relying solely on the next scheduled retry — merchant retry cadence is not visible to FlexFactor. The Sync MIT comparison table lists the event as a completion backstop. | workflows.md §2.5 |
2026-08-06
| Type | Area | Change | Pages |
|---|---|---|---|
| Removed | Webhooks | payout.created and payout.updated are no longer part of the documented webhook event set. | webhooks-1.md |
| Clarified | Webhooks | order.capturerequired also fires on all Sync MIT approvals — Sync MIT uses auth/capture regardless of transactionType. | webhooks-1.md |
2026-06-30
| Type | Area | Change | Pages |
|---|---|---|---|
| Added | Idempotency | Full idempotency behavior documented: GUID idempotencyKey sent in the JSON body (not a header), 24-hour replay window, per-merchant scope, natural-key safeguards, and a response/retry reference covering 409 in-flight, 409 reused-key conflict, 500 unknown-outcome, and 503 idempotency-store-unavailable (Retry-After, safe to retry). Documented as §3.4 in Workflows. | workflows.md |
| Added | OpenAPI schema | /v1/capture, /v1/orders/{id}/cancel, and /v1/orders/{external-order-id}/external-cancel added to flexfactor-v1.json (previously undocumented in the spec). New schemas CaptureRequest, CaptureResult, CancelRequest. idempotencyKey is required on CaptureRequest, optional on CancelRequest. All three carry 409/503 idempotency responses. | reference (flexfactor-v1.json) |
| Added | /v1/orders/{id}/refund | RefundRequest now includes an optional idempotencyKey (GUID, JSON body), in both the OpenAPI schema and the docs. 409/503 responses added to the refund path. | refund.md, reference |
| Clarified | /v1/orders/{id}/refund | Full refunds are de-duplicated server-side by order ID; partial refunds are not — integrators must send an idempotencyKey on partial refunds to prevent duplicate partial credits. | refund.md, workflows.md |
| Added | /v1/orders/{id}/cancel, /v1/orders/{external-order-id}/external-cancel | Accept an optional idempotencyKey (GUID, JSON body); cancel remains guarded server-side via the order ID even with no key. External-cancel is keyed by the same underlying order as cancel. | cancel.md, reference |
| Clarified | /v1/evaluate, /v1/capture | idempotencyKey (already required) now documents replay-of-original-response and 409 conflict-detection behavior, with a cross-link to the Idempotency reference. 409/503 responses added to the /v1/evaluate path in the spec. | evaluate.md, capture.md, reference |
| Clarified | Error handling | Added 409 Conflict to the status-code and retry tables; noted that a 503 from the idempotency store (carries Retry-After, safe to retry) is distinct from a rescue-availability 503 (do not retry). | errors.md |
2026-06-12
| Type | Area | Change | Pages |
|---|---|---|---|
| Changed | /v1/evaluate | subscription required-ness corrected: required when isMIT and isRecurring are both true (previously listed as optional in the MIT parameters table). Optimization Rank: Required — MIT. Docs-only correction — the API has always enforced this. | evaluate.md |
| Added | /v1/evaluate | subscription.intervalCount — optional int, defaults to 1. Number of interval units between payments. Existing API field, previously undocumented. | evaluate.md |
2026-06-04
| Type | Area | Change | Pages |
|---|---|---|---|
| Added | /v1/evaluate | attemptCount — new optional root-level request field, type integer (OpenAPI FlexFactor-V1). Tells FlexFactor which authorization attempt this request represents (1 = original attempt, 2 = first retry, and so on). Optimization Rank: High. | evaluate.md, evaluate-api.md |
2026-06-01
| Type | Area | Change | Pages |
|---|---|---|---|
| Changed | Branding | All public-facing URLs and embedded references consolidated to flexfactor.io. OpenAPI info.title is now FlexFactor-V1 (source file published as flexfactor-v1.json). The recipes/authentication.md recipe URL is now canonical. The SFTP host sftp.flex-charge.com remains in place pending a separate migration. | — |
| Deprecated | /v1/outcome | Marked deprecated: true in both the markdown frontmatter and the OpenAPI path; reference page hidden from public navigation. Use GET /v1/orders/{id} for current order status. | outcome.md |
| Added | Webhooks | Events payment.chargeback.reversed and payment.early_warning.received (Recommended tier). | webhooks-1.md |
| Changed | Error handling | Retry rules now stated explicitly: 401 refresh access token once; 500 / 502 / 504 exponential backoff (max 3 attempts); 503 fall back to original decline and do not retry. 504 Gateway Timeout added to the response-code table. | errors.md |
| Added | Webhooks | Source-IP allowlist documented: Production 18.233.184.33, 52.4.241.101; Sandbox 35.172.5.145, 3.211.16.180. | webhooks-1.md |
| Added | SFTP | Connection details added (host, port, ed25519 recommended). | ssh-key-generation.md |
| Renamed | OpenAPI schema | threeDsecure key casing corrected to threeDSecure to match prose and reference documentation. | — |
| Clarified | /v1/orders/{id}/refund, /v1/orders/{id}/cancel | idempotencyKey is not required; idempotency is enforced server-side via the order ID. (Superseded by the 2026-06-30 entry: partial refunds are not de-duplicated; provide an idempotencyKey.) | — |
| Clarified | /v1/evaluate | expiryDateUtc now documents the 21-day default rescue window. | evaluate.md |
| Clarified | /v1/evaluate | Capture-required status now references the 5-minute default capture window for Authorize flows. | evaluate.md |
| Changed | /v1/evaluate | threeDSecure documented as an optional passthrough object on all flows, including MIT and recurring transactions. | evaluate.md |
| Added | Introduction | Integration prerequisites section covering the four standing assumptions: amount-in-cents, expiry ISO-UTC parsing, GDPR / data minimization, PCI AOC. | introduction.md |
Earlier historyChange history begins on 6/1/2026.
Updated 4 days ago

