Alerts and Decisioning API
Programmatically receives and decisions Payment Holds, automating your fraud review and hold resolution workflow to minimize operational delays while adhering to corporate IT standards.
Programmatically receives and decisions Payment Holds, automating your fraud review and hold resolution workflow to minimize operational delays while adhering to corporate IT standards.
# Harvested verbatim from the J.P. Morgan Payments Developer Portal.
# method: searched
# source: https://developer.payments.jpmorgan.com/api/llm-content?path=en%2Fapi%2Ffraud-solutions%2Falerts-and-decisioning%2Foas.md
# generated: '2026-07-28'
openapi: 3.1.0
info:
title: Alerts and Decisioning API
version: 1.0.5
contact:
name: JPMorgan Chase & Co. API support
email: ismd.security.operations@jpmorgan.com
url: https://apistore.jpmchase.net/support/contact
description: 'Programmatically receives and decisions Payment Holds, automating your fraud review and
hold resolution workflow to minimize operational delays while adhering to corporate IT standards.
'
servers:
- url: https://api.payments.jpmorgan.com/trust-safety/v1
description: PRODUCTION - MTLS
- url: https://api-cat.payments.jpmorgan.com/trust-safety/v1
description: CLIENT TESTING - MTLS
- url: https://api-mock.payments.jpmorgan.com/trust-safety/v1
description: MOCK
tags:
- name: Health
description: Service Health Checks
- name: Payment Holds
description: Manage Payment Holds
paths:
/health:
get:
summary: Shallow Health Check
description: '**Shallow Health Check**
Returns the health status of the API service. This endpoint performs a lightweight check
to confirm the service is running and able to accept requests. It does not verify
downstream dependencies.
'
tags:
- Health
operationId: getHealth
responses:
'200':
description: Service is healthy
content:
application/json:
schema:
$ref: '#/components/schemas/HealthStatus'
example:
status: UP
isReady: true
version: 2.1.0
applicationName: Example App
statusUpdatedAt: '2025-09-25T12:00:00Z'
'400':
description: Bad Request
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
example:
title: Invalid Data
httpStatus: 400
traceId: 0eca2e1a-74b7-44b7-9e66-4a6ec8336eb9
requestId: d3dd646b-1fd0-4389-b6b4-0c3ab486bvg1
context:
- code: '10104'
message: Bad Value
location: BODY
field: type
'401':
description: Unauthorized - Authentication credentials are missing or invalid.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
example:
title: Authentication Failure
httpStatus: 401
traceId: 0eca2e1a-74b7-44b7-9e66-4a6ec8336eb9
requestId: d3dd646b-1fd0-4389-b6b4-0c3ab486bvg1
context:
- code: '14000'
message: Client could not be authenticated
'403':
description: Forbidden. The client does not have the required permissions to access this resource.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
example:
title: Authorization Failure
httpStatus: 403
traceId: 0eca2e1a-74b7-44b7-9e66-4a6ec8336eb9
requestId: d3dd646b-1fd0-4389-b6b4-0c3ab486bvg1
context:
- code: '14000'
message: Client forbidden from accessing the requested resource
'503':
description: Service Unavailable
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
example:
title: Service Unavailable
httpStatus: 503
context:
- code: '12000'
message: Service Unavailable
/holds:
get:
summary: Retrieve Payment Holds
description: '**Retrieve payment holds**
Returns a paginated list of payment holds, optionally filtered by status, substatus, and date
range.
#### Filtering by `status` vs `substatus`
The `status` and `substatus` query parameters are **mutually exclusive** — you may use one or
the other, but not both in the same request. If both are provided, the API will return a `400
Bad Request` error.
Use **`status`** for broad filtering based on the high-level state of a hold:
| Value | Description |
|-------|-------------|
| `PENDING` | Returns all holds awaiting a decision, regardless of whether they are pending client
action or bank review |
| `APPROVED` | Returns holds that have been approved |
| `REJECTED` | Returns holds that have been rejected. Can use both `APPROVED` and `REJECTED` together
to retrieve all decisioned holds. |
Use **`substatus`** for more granular filtering when you need to distinguish _who_ needs to act
or _how_ a hold was resolved:
| Value | Description |
|-------|-------------|
| `PENDING_ACTION_CLIENT` | Holds awaiting a decision by the client |
| `PENDING_ACTION_JPM` | Holds under review by the bank |
Can also use substatus to filter for holds decisioned by specific entity (client or JPM) or for
a particular reason.
If neither parameter is provided, holds across all statuses are returned.
'
tags:
- Payment Holds
operationId: getPaymentHolds
x-parameter-constraints:
- type: mutually-exclusive
params:
- status
- substatus
parameters:
- $ref: '#/components/parameters/Status'
- $ref: '#/components/parameters/substatus'
- $ref: '#/components/parameters/StartDateTime'
- $ref: '#/components/parameters/EndDateTime'
- $ref: '#/components/parameters/Sort'
- $ref: '#/components/parameters/Offset'
- $ref: '#/components/parameters/PageSize'
responses:
'200':
description: Retrieve Payment Holds
headers:
Cache-Control:
schema:
type: string
default: no-store
description: Caching directive for sensitive financial data
content:
application/json:
schema:
$ref: '#/components/schemas/PaymentHolds'
examples:
Pending Client Action:
$ref: '#/components/examples/PendingClientDecisionResponse'
Pending JPM Review:
$ref: '#/components/examples/PendingBankDecisionResponse'
Pending Bank Or Client Decision:
$ref: '#/components/examples/PendingBankOrClientDecisionResponse'
Already Decisioned:
$ref: '#/components/examples/AlreadyDecisionedResponse'
'400':
description: "Bad Request. \n\n**List of error codes and descriptions**\n\n| Error Code \
\ | Description |\n| -------------- |------------------------------------------------|\n\
| 10001 | Mandatory field missing or invalid |\n| 10103 |\
\ Bad Format |\n| 10104 | Bad Value \
\ |\n| 10108 | Mutually exclusive fields violation\
\ |"
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
examples:
Bad Status:
$ref: '#/components/examples/BadIdentifier'
Filter By Status And Substatus (Not Allowed):
$ref: '#/components/examples/FilterByStatusAndSubstatusErrorResponse'
'401':
$ref: '#/components/responses/401-Unauthorized'
'403':
$ref: '#/components/responses/403-Forbidden'
'429':
$ref: '#/components/responses/429-TooManyRequests'
'503':
$ref: '#/components/responses/503-ServiceUnavailable'
/holds/{id}:
get:
summary: Retrieve details of a payment hold
description: '**Retrieve details of a single payment hold by identifier**'
tags:
- Payment Holds
operationId: getPaymentHoldDetails
parameters:
- name: id
in: path
description: Unique identifier for the payment hold
required: true
schema:
$ref: '#/components/schemas/Uuid'
examples:
By Id:
value: 06bca14f-1fc0-4cd7-9e0b-8bb7e06334f7
responses:
'200':
description: Payment Hold Details
headers:
Cache-Control:
schema:
type: string
default: no-store
description: Caching directive for sensitive financial data
content:
application/json:
schema:
$ref: '#/components/schemas/PaymentHold'
examples:
Wire Transfer:
$ref: '#/components/examples/RetrieveSingleHoldResponse'
ACH Distributed:
$ref: '#/components/examples/RetrieveSingleHoldAchDistributedResponse'
'400':
description: 'Bad Request.
**List of error codes and descriptions**
| Error Code | Description |
| -------------- |------------------------------------------------|
| 10103 | Bad Format |
| 11004 | Wrong channel for hold |'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
examples:
Bad Identifier:
$ref: '#/components/examples/BadIdentifier'
Wrong Channel:
value:
title: Bad Request
httpStatus: 400
traceId: 00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01
requestId: 123e4567-e89b-12d3-a456-426614174000
context:
- code: '11004'
message: Wrong channel for hold
'401':
$ref: '#/components/responses/401-Unauthorized'
'403':
$ref: '#/components/responses/403-Forbidden'
'404':
$ref: '#/components/responses/404-NotFound'
'429':
$ref: '#/components/responses/429-TooManyRequests'
'503':
$ref: '#/components/responses/503-ServiceUnavailable'
/holds/{id}/decision:
post:
summary: Decision Single Payment Hold
description: '**Decision Single Payment Hold**
This endpoint allows users to take action on a single payment hold by approving or rejecting it. Users
can specify the decision action (APPROVE or REJECT), provide a reason for rejection, and indicate
the type of confirmed fraud if applicable. For bulk processing of multiple hold decisions, use
the `/holds/decision/bulk` endpoint instead.'
tags:
- Payment Holds
operationId: decisionPaymentHold
parameters:
- name: id
in: path
description: Unique identifier for the payment hold
required: true
schema:
$ref: '#/components/schemas/Uuid'
examples:
Approve:
value: f1c2b3a4-5d6e-4f70-8a9c-1234abcd5678
Reject:
value: 550e8400-e29b-41d4-a716-446655440000
Expired:
value: 9b1d3f2a-6c8e-4f5a-9d2b-3e7a1c4b8d90
Already Decisioned:
value: 3d6f9a2c-5e47-4b1f-8c3a-0d2e7f9b6a10
requestBody:
required: true
description: Hold Action
content:
application/json:
schema:
$ref: '#/components/schemas/DecisionActionRequest'
examples:
Approve:
$ref: '#/components/examples/HoldDecisionApproveActionRequest'
Reject:
$ref: '#/components/examples/HoldDecisionRejectActionRequest'
Incorrect Field Values:
$ref: '#/components/examples/HoldBadValuesRequest'
responses:
'200':
description: Decision response for the payment hold action
content:
application/json:
schema:
$ref: '#/components/schemas/DecisionResponse'
examples:
Approve:
$ref: '#/components/examples/HoldDecisionApproveActionResponse'
Reject:
$ref: '#/components/examples/HoldDecisionRejectActionResponse'
'400':
description: "Bad Request. \n\n**List of error codes and descriptions**\n\n| Error Code \
\ | Description |\n| -------------- |----------------------------------------------------------|\n\
| 10001 | Mandatory field missing |\n| 10103 \
\ | Bad format |\n| 10104 \
\ | Bad Value |\n| 11003 | Field\
\ only allowed for specific value of other field |"
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
examples:
Bad Identifier:
$ref: '#/components/examples/BadIdentifier'
'401':
$ref: '#/components/responses/401-Unauthorized'
'403':
$ref: '#/components/responses/403-Forbidden'
'404':
$ref: '#/components/responses/404-NotFound'
'409':
description: 'Conflict
**List of error codes and descriptions**
| Error Code | Description |
| -------------- |------------------------------------------------|
| 11000 | Hold has expired |
| 11001 | Hold already decisioned |
| 11004 | Wrong channel for hold |
**Hold Already Decisioned (11001):** A payment hold may only be decisioned once. In rare cases,
two users may attempt to decision the same hold at nearly the same time. When this occurs,
only the first request will succeed — the subsequent request will receive a `409 Conflict`
with error code `11001`. While this scenario is uncommon, API consumers must handle this response
gracefully.'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
examples:
Expired:
$ref: '#/components/examples/HoldExpiredResponse'
Already Decisioned:
$ref: '#/components/examples/HoldAlreadyDecisionedResponse'
Wrong Channel:
value:
title: Conflict
httpStatus: 409
traceId: 00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01
requestId: 123e4567-e89b-12d3-a456-426614174000
context:
- code: '11004'
message: Wrong channel for hold
Incorrect Field Values:
$ref: '#/components/examples/HoldBadValuesResponse'
'429':
$ref: '#/components/responses/429-TooManyRequests'
'503':
$ref: '#/components/responses/503-ServiceUnavailable'
/holds/decision/bulk:
post:
summary: Decision Multiple Payment Holds (Bulk)
description: '**Decision Multiple Payment Holds (Bulk)**
This endpoint allows users to take action on multiple payment holds simultaneously by approving
or rejecting them. The API supports batch processing of multiple hold decisions, enabling efficient
processing of large volumes of holds. Each decision in the batch can have its own action (APPROVE
or REJECT), rejection reason, and confirmed fraud type. For processing a single hold decision,
use the `/holds/{id}/decision` endpoint instead.'
tags:
- Payment Holds
operationId: decisionPaymentHoldsBulk
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/DecisionBulkRequest'
examples:
Mixed Results:
$ref: '#/components/examples/HoldDecisionManyRequest'
responses:
'200':
description: Bulk response object containing decision responses for each hold
content:
application/json:
schema:
$ref: '#/components/schemas/DecisionBulkResponse'
examples:
Mixed Results:
$ref: '#/components/examples/HoldDecisionManyResponse'
'400':
description: 'Bad Request.
**List of error codes and descriptions**
| Error Code | Description |
| -------------- |------------------------------------------------|
| 10001 | Mandatory field missing or invalid |
| 10103 | Bad Format |
| 10104 | Bad Value |'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
examples:
Bad Identifier:
$ref: '#/components/examples/BadIdentifier'
'401':
$ref: '#/components/responses/401-Unauthorized'
'403':
$ref: '#/components/responses/403-Forbidden'
'409':
description: 'Conflict
**List of error codes and descriptions**
| Error Code | Description |
| -------------- |------------------------------------------------|
| 11000 | Hold has expired |
| 11001 | Hold already decisioned |'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
examples:
Expired:
$ref: '#/components/examples/HoldExpiredResponse'
Already Decisioned:
$ref: '#/components/examples/HoldAlreadyDecisionedResponse'
'429':
$ref: '#/components/responses/429-TooManyRequests'
'503':
$ref: '#/components/responses/503-ServiceUnavailable'
webhooks:
Payment:
post:
summary: Payment Hold Notification
operationId: webHookPaymentHoldNotification
description: 'Fired when a payment hold event occurs. The `type` field in the CloudEvents envelope
determines the specific event:
| Event Type | Description |
|------------|-------------|
| com.jpmorgan.payments.payment.hold.placed.`v1` | A payment has been held for review. The payload
contains the complete hold including the payment details. |
| com.jpmorgan.payments.payment.hold.ammended.`v1` | A payment hold has been updated (decisioned,
distributed, reassigned). The payload includes the updated status/substatus, decision and distribution,
if applicable. |
| com.jpmorgan.payments.payment.hold.closed.`v1` | A payment hold has been closed. This event
occurs when the hold is decisioned by the bank or when the decision is changed after payment distribution
to notify JPMC about true fraud. NOTE: This event is only emitted when JPMC changes hold status/substatus
and is NOT emitted when you decision a hold via API. |
'
tags:
- Notifications
x-codegen-request-body-name: body
requestBody:
description: Payment Hold Notification
required: true
content:
application/cloudevents+json:
schema:
$ref: '#/components/schemas/Notification'
examples:
PaymentHeldWireTransfer:
description: 'com.jpmorgan.payments.payment.hold.placed.v1 notification for a wire transfer.
Represents hold creation — contains the complete hold including the payment. No decision
yet.
'
summary: Payment Held – Wire Transfer
value:
specversion: '1.0'
id: 7d2a159b-9c3a-4db2-bd03-e64047c32917
time: '2026-02-01T14:15:22Z'
type: com.jpmorgan.payments.payment.hold.placed.v1
source: api.payments.jpmorgan.com/trust-safety/v1
dataschema: urn:com.jpmorgan.payments/payment-hold
data:
id: 06bca14f-1fc0-4cd7-9e0b-8bb7e06334f7
status: PENDING
substatus: PENDING_ACTION_CLIENT
cutOffAt: '2026-02-06T14:15:22Z'
rules:
- id: 59be9844-3a70-4fbc-8d58-9637c1b34b18
name: Client ABC Rule for Suspicious Beneficiary
effectiveAt: '2019-08-24'
payment:
requestedExecutionDate: '2026-02-01'
paymentIdentifiers:
endToEndId: E2E3000113WEBXX
value:
currency: USD
amount: '10.50'
transferType: DEBIT
paymentType: WIRE
debtorAgent:
financialInstitutionIds:
- id: CHASUS33XXX
idType: BIC
debtor:
name: Nicholas Tesla
account:
accountNumber: '987654321'
accountCurrency: USD
postalAddress:
type: HOME
addressLines:
- 10007 S. Lake Drive
streetName: 10007 Lake Dr
postalCode: '48035'
city: Clinton Township
countrySubDivision: MI
country: US
creditor:
name: Comrade Musics
account:
accountNumber: '123456011'
accountCurrency: USD
postalAddress:
country: US
PaymentHeldAch:
description: 'com.jpmorgan.payments.payment.hold.placed.v1 notification for an outgoing
ACH payment.
Represents hold creation — contains the complete hold including the payment. No decision
yet.
'
summary: Payment Held – Outgoing ACH
value:
specversion: '1.0'
id: c3a81f29-47d6-4e8b-a5c1-9f6b2d4e7a03
time: '2026-02-10T09:45:00Z'
type: com.jpmorgan.payments.payment.hold.placed.v1
source: api.payments.jpmorgan.com/trust-safety/v1
dataschema: urn:com.jpmorgan.payments/payment-hold
data:
id: 253f67f3-b640-44cb-aabd-2cc348b52678
status: PENDING
substatus: PENDING_ACTION_CLIENT
cutOffAt: '2026-02-15T09:45:00Z'
rules:
- id: a4e7c910-6b3d-4f2a-8c15-d9f0e1b23456
name: ACH Amount Threshold Rule
effectiveAt: '2025-06-01'
payment:
requestedExecutionDate: '2026-02-10'
paymentIdentifiers:
endToEndId: E2E3000112CCDXX
value:
currency: USD
amount: '5250.00'
transferType: CREDIT
paymentType: ACH
debtorAgent:
financialInstitutionIds:
- id: CHASUS33XXX
idType: BIC
debtor:
name: Acme Corp
account:
accountNumber: '12311871'
accountCurrency: USD
postalAddress:
country: US
creditor:
name: Kelly Thomas
account:
accountNumber: '87654321'
postalAddress:
country: US
PaymentHeldRtp:
description: 'com.jpmorgan.payments.payment.hold.placed.v1 notification for a US Real-Time
Payment (RTP).
Represents hold creation — contains the complete hold including the payment. No decision
yet.
'
summary: Payment Held – US RTP
value:
specversion: '1.0'
id: f8d24a61-3b92-4c7e-a0d5-1e9f6c8b7a42
time: '2026-02-12T16:20:00Z'
type: com.jpmorgan.payments.payment.hold.placed.v1
source: api.payments.jpmorgan.com/trust-safety/v1
dataschema: urn:com.jpmorgan.payments/payment-hold
data:
id: d7e3f1a9-4c82-4b6d-9a0e-5f2c8d1b3e70
status: PENDING
substatus: PENDING_ACTION_JPM
cutOffAt: '2026-02-12T17:20:00Z'
reasons:
- Unusual RTP amount flagged by fraud screening
payment:
requestedExecutionDate: '2026-02-12'
paymentIdentifiers:
endToEndId: E2E3000114RTPXX
value:
currency: USD
amount: '25000.00'
transferType: CREDIT
paymentType: RTP
debtorAgent:
financialInstitutionIds:
- id: '021000021'
idType: USABA
debtor:
name: Global Imports LLC
account:
accountNumber: '445566778'
accountCurrency: USD
postalAddress:
city: New York
countrySubDivision: NY
country: US
creditor:
name: Oceanic Trading Co
account:
accountNumber: '112233445'
accountCurrency: USD
postalAddress:
country: US
HoldAmendedAch:
description: 'com.jpmorgan.payments.payment.hold.ammended.v1 notification for an outgoing
ACH hold that was approved by the client.
'
summary: Hold Updated – ACH Approved
value:
specversion: '1.0'
id: b2d4e6f8-1a3c-5d7e-9f0b-2c4d6e8a0b12
time: '2026-02-11T11:00:00Z'
type: com.jpmorgan.payments.payment.hold.ammended.v1
source: api.payments.jpmorgan.com/trust-safety/v1
dataschema: urn:com.jpmorgan.payments/payment-hold
data:
id: 253f67f3-b640-44cb-aabd-2cc348b52678
status: APPROVED
substatus: APPROVED_CLIENT
decision:
source: API
HoldAmendedWireTransfer:
description: 'com.jpmorgan.payments.payment.hold.ammended.v1 notification for a wire transfer
hold that was rejected as fraud.
'
summary: Hold Updated – Wire Transfer Rejected (Fraud)
value:
specversion: '1.0'
id: a1c9e3d7-82f4-4b6a-9d1e-3f7c8a2b5e90
time: '2026-02-03T09:30:00Z'
type: com.jpmorgan.payments.payment.hold.ammended.v1
source: api.payments.jpmorgan.com/trust-safety/v1
dataschema: urn:com.jpmorgan.payments/payment-hold
data:
id: 06bca14f-1fc0-4cd7-9e0b-8bb7e06334f7
status: REJECTED
substatus: REJECTED_FRAUD_JPM
decision:
source: API
rejectReason: FRAUD
fraud:
type: OTHER
additionalInformation: Suspicious wire transfer to unknown beneficiary
HoldAmendedRtp:
description: 'com.jpmorgan.payments.payment.hold.ammended.v1 notification for a US RTP
hold that was auto-cancelled due to expiration.
'
summary: Hold Updated – RTP Auto-Cancelled
value:
specversion: '1.0'
id: e9f1a3b5-c7d9-4e2f-b0a4-6d8c1e3f5a72
time: '2026-02-12T17:20:01Z'
type: com.jpmorgan.payments.payment.hold.ammended.v1
source: api.payments.jpmorgan.com/trust-safety/v1
dataschema: urn:com.jpmorgan.payments/payment-hold
data:
id: d7e3f1a9-4c82-4b6d-9a0e-5f2c8d1b3e70
status: REJECTED
substatus: REJECTED_AUTO_CANCELLED_JPM
decision:
source: JPMC_UI
rejectReason: TRANSACTION_NO_LONGER_NEEDED
HoldClosedByJpmReview:
description: 'com.jpmorgan.payments.payment.hold.closed.v1 notification when a hold is
closed by JPM review.
'
summary: Hold Closed – Closed by JPM Review
value:
specversion: '1.0'
id: b4d82e1f-6a93-4c7b-8e2d-9f1a3c5d7b60
time: '2026-02-05T11:20:00Z'
type: com.jpmorgan.payments.payment.hold.closed.v1
source: api.payments.jpmorgan.com/trust-safety/v1
dataschema: urn:com.jpmorgan.payments/payment-hold
data:
id: 06bca14f-1fc0-4cd7-9e0b-8bb7e06334f7
status: REJECTED
substatus: REJECTED_FRAUD_JPM
decision:
source: API
rejectReason: FRAUD
fraud:
type: BUSINESS_EMAIL_COMPROMISE
HoldClosedTrueFraudAfterDistribution:
description: 'com.jpmorgan.payments.payment.hold.closed.v1 notification when true fraud
is reported after payment distribution.
'
summary: Hold Closed – True Fraud Reported After Payment Distribution
value:
specversion: '1.0'
id: e7f19c4a-2d85-4b3e-a6c1-8d4f2e9b7a13
time: '2026-02-08T14:45:00Z'
type: com.jpmorgan.payments.payment.hold.closed.v1
source: api.payments.jpmorgan.com/trust-safety/v1
dataschema: urn:com.jpmorgan.payments/payment-hold
data:
id: 06bca14f-1fc0-4cd7-9e0b-8bb7e06334f7
status: REJECTED
# --- truncated at 32 KB (113 KB total) ---
# Full source: https://raw.githubusercontent.com/api-evangelist/jp-morgan-chase/refs/heads/main/openapi/jp-morgan-chase-alerts-and-decisioning-api-openapi.yml