API integration guide
Full API documentation is available here: https://api.chargebackstop.com/v1/docs.
V2 API documentation (enrolments endpoint only for now): https://api.chargebackstop.com/v2/docs.
Onboarding a new customer into your partner account
Section titled “Onboarding a new customer into your partner account”-
Create an organisation
Section titled “Create an organisation”Use the
/v1/organisationsendpoint. Save the organisation ID for later use in the memberships and merchants APIs.Sample request:
curl -X POST "https://api.chargebackstop.com/v1/organisations/" \-H "Authorization: Bearer <partner_api_key>" \-H "Content-Type: application/json" \-d '{"name": "Acme Fitness"}'Sample response:
{"id": "org_abc123","name": "Acme Fitness","mode": "LIVE","created_at": "2026-02-17T10:00:00Z","updated_at": "2026-02-17T10:00:00Z"}Save
organisation_id = org_abc123. You will use this in memberships, merchants, and integrations requests. -
Add your customer users to their organisation
Section titled “Add your customer users to their organisation”Use the
/v1/membershipsendpoint.You can skip this step if you do not intend for your users to log in to ChargebackStop.
Sample request:
curl -X POST "https://api.chargebackstop.com/v1/memberships/" \-H "Authorization: Bearer <partner_api_key>" \-H "Content-Type: application/json" \-d '{"organisation_id": "org_abc123","first_name": "Casey","last_name": "Jordan","email": "casey.jordan@acmefitness.com","role": "ADMIN","is_alert_action_required_email_enabled": true,"is_alert_resolved_email_enabled": true,"is_alert_dismissed_email_enabled": true,"is_evidence_requested_email_enabled": true}'Sample response:
{"id": "mem_abc123","organisation_id": "org_abc123","user_id": "usr_abc123","first_name": "Casey","last_name": "Jordan","email": "casey.jordan@acmefitness.com","role": "ADMIN","is_alert_action_required_email_enabled": true,"is_alert_resolved_email_enabled": true,"is_alert_dismissed_email_enabled": true,"is_evidence_requested_email_enabled": true,"created_at": "2026-02-17T10:01:00Z","updated_at": "2026-02-17T10:01:00Z"}This creates the customer user and links them to the organisation.
-
Add their merchant accounts into the newly created organisation
Section titled “Add their merchant accounts into the newly created organisation”Use the
/v1/merchantsendpoint. Save the merchant account IDs for later use in the integrations and enrolments APIs.Sample request:
curl -X POST "https://api.chargebackstop.com/v1/merchants/" \-H "Authorization: Bearer <partner_api_key>" \-H "Content-Type: application/json" \-d '{"organisation_id": "org_abc123","name": "Acme Fitness Main Store","type": "GENERIC","external_id": "acct_1ABCDEF2345678"}'Sample response:
{"id": "mrch_abc123","organisation_id": "org_abc123","name": "Acme Fitness Main Store","type": "GENERIC","external_id": "acct_1ABCDEF2345678","default_representment_service_type": null,"created_at": "2026-02-17T10:02:00Z","updated_at": "2026-02-17T10:02:00Z"}Save
merchant_id = mrch_abc123. You will use this in integrations and enrolments requests. -
If you intend to use the Orders API, create an integration
Section titled “If you intend to use the Orders API, create an integration”Use the
/v1/integrationsendpoint. Save the integration ID for later use in the orders API.Sample request:
curl -X POST "https://api.chargebackstop.com/v1/integrations/" \-H "Authorization: Bearer <partner_api_key>" \-H "Content-Type: application/json" \-d '{"organisation_id": "org_abc123","name": "Acme Fitness Orders","type": "CUSTOM_ORDERS","status": "ENABLED","merchant_ids": ["mrch_abc123"]}'Sample response:
{"id": "int_abc123","organisation_id": "org_abc123","name": "Acme Fitness Orders","type": "CUSTOM_ORDERS","status": "ENABLED","merchant_ids": ["mrch_abc123"]}Save
integration_id = int_abc123. You will use this for orders submissions. -
If you wish to enrol the customer with Ethoca or Verifi RDR, create enrolments
Section titled “If you wish to enrol the customer with Ethoca or Verifi RDR, create enrolments”Use the
/v2/enrolmentsendpoint. Verifi RDR and Ethoca enrolments are separate; create both if the customer wants both services.See Enrolments API docs.
Create Ethoca enrolment
Sample request:
curl -X POST "https://api.chargebackstop.com/v2/enrolments/" \-H "Authorization: Bearer <partner_api_key>" \-H "Content-Type: application/json" \-d '{"merchant_ids": ["mrch_abc123"],"type": "ETHOCA_ALERT","ethoca_alert": {"descriptors": [{"descriptor": "ACMEFIT","match_type": "STARTS_WITH"}]}}'Sample response:
{"id": "enrl_ethoca123","organisation_id": "org_abc123","merchant_ids": ["mrch_abc123"],"type": "ETHOCA_ALERT","status": "PENDING","ethoca_alert": {"descriptors": [{"descriptor": "ACMEFIT","match_type": "STARTS_WITH","status": "PENDING"}]},"created_at": "2026-02-17T10:03:00Z","updated_at": "2026-02-17T10:03:00Z","note": null}Save
ethoca_enrolment_id = enrl_ethoca123if you need to track this enrolment status.Create Verifi RDR enrolment
Sample request:
curl -X POST "https://api.chargebackstop.com/v2/enrolments/" \-H "Authorization: Bearer <partner_api_key>" \-H "Content-Type: application/json" \-d '{"merchant_ids": ["mrch_abc123"],"type": "VERIFI_RDR","verifi_rdr": {"bin": "424242","caid": "ABC1234567"}}'You must provide either both
binandcaid, or at least one ARN in thearnsarray. For example, to enrol using ARNs instead:{"merchant_ids": ["mrch_abc123"],"type": "VERIFI_RDR","verifi_rdr": {"arns": ["74027012345678901234567"]}}Sample response:
{"id": "enrl_verifi123","organisation_id": "org_abc123","merchant_ids": ["mrch_abc123"],"type": "VERIFI_RDR","status": "PENDING","verifi_rdr": {"bin": "424242","caid": "ABC1234567"},"created_at": "2026-02-17T10:04:00Z","updated_at": "2026-02-17T10:04:00Z","note": null}Save
verifi_enrolment_id = enrl_verifi123if you need to track this enrolment status.Note: Once the enrolment is enabled (2-3 business days for Ethoca, and up to 5-14 business days for Verifi RDR), your customer will start receiving pre-dispute alerts in their organisation.
-
Optional: Configure resolution rules for the new enrolments
Section titled “Optional: Configure resolution rules for the new enrolments”Use the
/v1/rulesetsendpoint to control what happens when a pre-dispute alert matches a transaction. A ruleset is scoped to one or more enrolments of the same type — you cannot combine Ethoca and Verifi RDR enrolments in the same ruleset. If you need the same logic for both, create one ruleset per enrolment type.See Rulesets API docs.
Verifi RDR
By default, every Verifi RDR alert results in a refund of the matching transaction. Verifi RDR alerts are resolved at the network level, so they arrive already resolved and have no
ACTION_REQUIREDstate — they are not actionable after the fact.If you want to limit which transactions are refunded — for example, never auto-refund transactions above a certain amount — create a ruleset with an
ACCEPT_DISPUTEoutcome and add rules describing the transactions that should bypass the default refund.Sample request — accept dispute (skip auto-refund) for any Verifi RDR transaction above $50:
curl -X POST "https://api.chargebackstop.com/v1/rulesets/" \-H "Authorization: Bearer <partner_api_key>" \-H "Content-Type: application/json" \-d '{"organisation_id": "org_abc123","enrolment_ids": ["enrl_verifi123"],"outcome": "ACCEPT_DISPUTE","join_operator": "AND","rules": [{"type": "AMOUNT","parameters": {"operator": "GREATER_THAN","currency_code": "USD","amount_in_cents": 5000}}]}'Ethoca
Resolution rules for Ethoca alerts only make sense if you have a payment processor integration in place (e.g. Stripe, Adyen) and ChargebackStop is matching incoming alerts to transactions. Ethoca alerts are actioned by issuing a refund through the original payment processor, so without a matched transaction there is nothing for a rule to act on.
Once matching is in place, a ruleset can auto-action matched Ethoca alerts that meet your criteria, so the user does not have to handle them manually.
Sample request — automatically refund and cancel matched Ethoca alerts whose descriptor starts with
ACMEFIT:curl -X POST "https://api.chargebackstop.com/v1/rulesets/" \-H "Authorization: Bearer <partner_api_key>" \-H "Content-Type: application/json" \-d '{"organisation_id": "org_abc123","enrolment_ids": ["enrl_ethoca123"],"outcome": "REFUND_AND_CANCEL","join_operator": "AND","rules": [{"type": "DESCRIPTOR","parameters": {"descriptors": [{"value": "ACMEFIT", "match_type": "STARTS_WITH"}]}}]}' -
Start pushing orders to us using the Orders API
Section titled “Start pushing orders to us using the Orders API”Use the
/v1/ordersendpoint.Send a COMPLETE order that satisfies alert matching requirements. COMPLETE orders can be sent directly to your
CUSTOM_ORDERSintegration.Sample request:
curl -X POST "https://api.chargebackstop.com/v1/orders/" \-H "Authorization: Bearer <partner_api_key>" \-H "Content-Type: application/json" \-d '[{"type": "COMPLETE","organisation_id": "org_abc123","integration_id": "int_abc123","reference_id": "order-10001","order_datetime": "2026-02-17T09:59:00Z","order_number": "AF-10001","order_subtotal_amount_in_cents": 4900,"order_currency": "USD","order_total_amount_in_cents": 4900,"order_status": "CLOSED_COMPLETE","customer_email": "casey.jordan@acmefitness.com","transactions": [{"reference_id": "txn-10001","amount_in_cents": 4900,"currency": "USD","payment_method_type": "CARD","authorisation_status": "SETTLED","payment_method_reference_id": "pi_3QJ2ABCD12345678","authorised_at": "2026-02-17T09:59:05Z","payment_method_card_brand": "VISA","payment_method_card_last_4": "4242","acquirer_reference_number": "74027012345678901234567"}]}]'Sample response:
{"created": 1,"failed": 0,"results": [{"id": "ord_abc123","reference_id": "order-10001","type": "COMPLETE","organisation_id": "org_abc123","integration_id": "int_abc123","created_at": "2026-02-17T10:05:00Z","transactions": [{"reference_id": "txn-10001","amount_in_cents": 4900,"currency": "USD","payment_method_type": "CARD","authorisation_status": "SETTLED","payment_method_card_brand": "VISA","payment_method_card_last_4": "4242","acquirer_reference_number": "74027012345678901234567"}]}],"errors": []}This creates a COMPLETE order with the core card transaction fields required for alert matching.
-
Optional: Run this flow with a Node.js script
Section titled “Optional: Run this flow with a Node.js script”If you want to run the same onboarding flow end-to-end and print all created IDs automatically, use:
node onboarding-flow.jsBefore running it, save the script below as
onboarding-flow.jsand setAPI_KEY.Full onboarding flow script (Node.js):
/** Simple onboarding flow example for partner API keys.** Update the variables in the CONFIG section, then run:* node onboarding-flow.js*/// -----------------------------------------------------------------------------// CONFIG// -----------------------------------------------------------------------------const API_BASE_URL = "https://api.chargebackstop.com";const API_KEY = "REPLACE_WITH_PARTNER_API_KEY";const MEMBER_USER_EMAIL = "test@example.com";const MEMBER_FIRST_NAME = "Casey";const MEMBER_LAST_NAME = "Jordan";const ORGANISATION_NAME = "Acme Fitness";const MERCHANT_NAME = "Acme Fitness Main Store";const MERCHANT_TYPE = "GENERIC";const MERCHANT_EXTERNAL_ID = "acct_1ABCDEF2345678";const INTEGRATION_NAME = "Acme Fitness Orders";const ORDER_REFERENCE_ID = "order-10001";const ORDER_NUMBER = "AF-10001";const ORDER_CUSTOMER_EMAIL = MEMBER_USER_EMAIL;const ORDER_TRANSACTION_REFERENCE_ID = "txn-10001";// -----------------------------------------------------------------------------// HELPERS// -----------------------------------------------------------------------------function fail(message, details) {console.error(`\nERROR: ${message}`);if (details !== undefined) {console.error(JSON.stringify(details, null, 2));}process.exit(1);}function logStep(stepNumber, title) {console.log(`\n[Step ${stepNumber}] ${title}`);}function printJson(label, data) {console.log(`${label}:`);console.log(JSON.stringify(data, null, 2));}async function apiRequest({ method, path, body }) {const response = await fetch(`${API_BASE_URL}${path}`, {method,headers: {Authorization: `Bearer ${API_KEY}`,"Content-Type": "application/json",},body: body ? JSON.stringify(body) : undefined,});const rawText = await response.text();let data = null;if (rawText.length > 0) {try {data = JSON.parse(rawText);} catch (error) {data = { raw: rawText };}}if (!response.ok) {fail(`Request failed: ${method} ${path} (${response.status})`, data);}return data;}// -----------------------------------------------------------------------------// FLOW// -----------------------------------------------------------------------------async function main() {if (API_KEY.includes("REPLACE_WITH_PARTNER_API_KEY")) {fail("Set API_KEY at the top of this file before running the script.");}const createdIds = {organisation_id: null,membership_id: null,merchant_id: null,integration_id: null,ethoca_enrolment_id: null,verifi_enrolment_id: null,order_id: null,};logStep(1, "Create organisation");const organisation = await apiRequest({method: "POST",path: "/v1/organisations/",body: {name: ORGANISATION_NAME,},});createdIds.organisation_id = organisation.id;printJson("Response", organisation);console.log(`Saved organisation_id: ${createdIds.organisation_id}`);logStep(2, "Create membership");const membership = await apiRequest({method: "POST",path: "/v1/memberships/",body: {organisation_id: createdIds.organisation_id,first_name: MEMBER_FIRST_NAME,last_name: MEMBER_LAST_NAME,email: MEMBER_USER_EMAIL,role: "ADMIN",is_alert_action_required_email_enabled: true,is_alert_resolved_email_enabled: true,is_alert_dismissed_email_enabled: true,is_evidence_requested_email_enabled: true,},});createdIds.membership_id = membership.id;printJson("Response", membership);console.log(`Saved membership_id: ${createdIds.membership_id}`);logStep(3, "Create merchant");const merchant = await apiRequest({method: "POST",path: "/v1/merchants/",body: {organisation_id: createdIds.organisation_id,name: MERCHANT_NAME,type: MERCHANT_TYPE,external_id: MERCHANT_EXTERNAL_ID,},});createdIds.merchant_id = merchant.id;printJson("Response", merchant);console.log(`Saved merchant_id: ${createdIds.merchant_id}`);logStep(4, "Create custom orders integration");const integration = await apiRequest({method: "POST",path: "/v1/integrations/",body: {organisation_id: createdIds.organisation_id,name: INTEGRATION_NAME,type: "CUSTOM_ORDERS",status: "ENABLED",merchant_ids: [createdIds.merchant_id],},});createdIds.integration_id = integration.id;printJson("Response", integration);console.log(`Saved integration_id: ${createdIds.integration_id}`);logStep(5, "Create Ethoca enrolment");const ethocaEnrolment = await apiRequest({method: "POST",path: "/v2/enrolments/",body: {merchant_ids: [createdIds.merchant_id],type: "ETHOCA_ALERT",ethoca_alert: {descriptors: [{descriptor: "ACMEFIT",match_type: "STARTS_WITH",},],},},});createdIds.ethoca_enrolment_id = ethocaEnrolment.id;printJson("Response", ethocaEnrolment);console.log(`Saved ethoca_enrolment_id: ${createdIds.ethoca_enrolment_id}`);logStep(6, "Create Verifi RDR enrolment");const verifiEnrolment = await apiRequest({method: "POST",path: "/v2/enrolments/",body: {merchant_ids: [createdIds.merchant_id],type: "VERIFI_RDR",verifi_rdr: {bin: "424242",caid: "ABC1234567",},},});createdIds.verifi_enrolment_id = verifiEnrolment.id;printJson("Response", verifiEnrolment);console.log(`Saved verifi_enrolment_id: ${createdIds.verifi_enrolment_id}`);logStep(7, "Submit COMPLETE order for alert matching");const orderResponse = await apiRequest({method: "POST",path: "/v1/orders/",body: [{type: "COMPLETE",organisation_id: createdIds.organisation_id,integration_id: createdIds.integration_id,reference_id: ORDER_REFERENCE_ID,order_datetime: "2026-02-17T09:59:00Z",order_number: ORDER_NUMBER,order_subtotal_amount_in_cents: 4900,order_currency: "USD",order_total_amount_in_cents: 4900,order_status: "CLOSED_COMPLETE",customer_email: ORDER_CUSTOMER_EMAIL,transactions: [{reference_id: ORDER_TRANSACTION_REFERENCE_ID,amount_in_cents: 4900,currency: "USD",payment_method_type: "CARD",authorisation_status: "SETTLED",payment_method_reference_id: "pi_3QJ2ABCD12345678",authorised_at: "2026-02-17T09:59:05Z",payment_method_card_brand: "VISA",payment_method_card_last_4: "4242",acquirer_reference_number: "74027012345678901234567",},],},],});printJson("Response", orderResponse);if (orderResponse.failed > 0) {console.log("\nOrder was not created. API returned validation errors.");} else if (orderResponse.results && orderResponse.results.length > 0) {createdIds.order_id = orderResponse.results[0].id;}console.log("\nDone. IDs to save for future requests:");printJson("Created IDs", createdIds);}main().catch((error) => {fail("Unexpected script error", {message: error.message,stack: error.stack,});});
Actioning alerts
Section titled “Actioning alerts”Every Ethoca alert with ACTION_REQUIRED status is expected to be actioned by the user. The deadline is represented by the action_required_deadline field in the alert object. However, we recommend sending your chosen action as soon as possible. After actioning, the alert status moves to RESOLVED and can no longer be changed. Verifi RDR alerts arrive already resolved and are not actionable.
Behind the scenes, actioning an alert updates Ethoca with the outcome. This allows them to stop the dispute if the user proactively refunded the transaction, or let the dispute proceed if you chose to fight it.
For actions that refund the transaction, if the merchant account is integrated with a payment provider (e.g. Stripe), we automatically refund the payment. You can also choose to cancel the subscription associated with the payment.
The update alert endpoint (PATCH /v1/alerts/{alert_id}) takes the following parameters:
action- the action to perform on the alert (see below)note- an optional customer-facing comment/note about the alert
The action parameter can be one of four values:
REFUNDCANCELREFUND_AND_CANCELACCEPT_DISPUTE
Let's explore how each of these values works.
REFUND
Section titled “REFUND”- We let the alert provider know that you refunded the alert.
- If your merchant account is integrated with a payment provider, we automatically refund the payment.
CANCEL
Section titled “CANCEL”- We let the alert provider know that you did not refund the alert.
- If your merchant account is integrated with a payment provider and there is a subscription associated with the alert, we automatically cancel it.
REFUND_AND_CANCEL
Section titled “REFUND_AND_CANCEL”- We let the alert provider know that you refunded the alert.
- If your merchant account is integrated with a payment provider, we automatically refund the payment.
- If your merchant account is integrated with a payment provider and there is a subscription associated with the alert, we automatically cancel it.
ACCEPT_DISPUTE
Section titled “ACCEPT_DISPUTE”- We let the alert provider know that you did not refund the alert.
If you have not integrated ChargebackStop with any payment processing services, you will most likely use only REFUND and ACCEPT_DISPUTE.
This API is also available to your customers. They can generate API keys for their own organisations in the organisation dashboard and action alerts via API.
Matching an alert to a transaction
Section titled “Matching an alert to a transaction”If you enabled payment processor integrations in your organisations and enabled automatic matching, GET /v1/alerts responses include two additional fields:
integration_id- ChargebackStop integration ID that contains the transaction matched to this alertintegration_transaction_id- transaction ID matched to this alert in your payment processor. For Stripe, this looks likepi_3SPJO4KRFSLReU4y04XJUvLN. For other processors it varies.
Resolution models: Ethoca vs Verifi RDR
Section titled “Resolution models: Ethoca vs Verifi RDR”Ethoca and Verifi RDR resolve alerts through fundamentally different mechanisms. Both flows are documented in detail in the sections above — use this contrast as a quick reference.
- Ethoca (
ETHOCA_ALERT) — Alerts enter anACTION_REQUIREDstate with a deadline (action_required_deadline). You (or your customer) must callPATCH /v1/alerts/{alert_id}with one ofREFUND,CANCEL,REFUND_AND_CANCEL, orACCEPT_DISPUTEbefore the deadline. If no action is taken, the dispute proceeds. Resolution rulesets can auto-action matched alerts when a payment processor integration is in place, but the underlying mechanism is still the samePATCHcall applied on the customer's behalf. - Verifi RDR (
VERIFI_RDR) — Alerts are resolved synchronously at the network level. Each incoming alert is evaluated against the enrolment's resolution ruleset and the chosen outcome is applied automatically. There is noACTION_REQUIREDstate, no deadline, and noPATCH /v1/alerts/{alert_id}call to make — the action API is Ethoca-only. With no ruleset configured, every RDR alert is refunded by default (see step 6 of the onboarding flow).
Test organisation simulations
Section titled “Test organisation simulations”In TEST mode, you can use simulation endpoints to test webhooks and actioning alerts.