# Real-time Decisioning

[API Documentation](/api/card-real-time-decisioning/real-time-decision-request-object)

Column allows your platform to make card authorization decisions in real-time. When Column receives authorization requests
from the card networks, the Bank will send a webhook to your system and await a decision. This functionality can be used
in conjunction with Column's authorization policy API to ensure only permitted transactions are approved.

## Decisioning Flow

When an approval request is received by Column from the card networks, the following approval process is followed:

1. Column will match the request to a Card & Card Account in the system. If Column cannot resolve the request to a card,
   it is automatically declined. If your platform is allocated an entire BIN, Column can send an event webhook when an
   authorization is declined due to an invalid account number on your behalf.
2. Column will check the status of the Card & Card Account, and if the status is not active, Column will decline the
   transaction with the appropriate decline code and send your system an event webhook.
3. Column checks the account type, address verification (AVS) results, and currency of the request, and declines the
   transaction if any of these checks fail.
4. Column evaluates any authorization policies configured by your system using the Authorization Policy API. If a policy
   is triggered, Column will decline the transaction on your behalf and send an event webhook.
5. Column performs fraud checks on the request.
6. Column will perform a balance check to ensure sufficient funds are available, if not, the transaction will be declined,
   and an event webhook will be sent to your system. Note: alternate funding models such as Just-in-time or transfer upon
   approval can be configured, please reach out to design a flow of funds if these models are needed.
7. Column will send a Real-time decision webhook to your system and will wait a total of 3 seconds for a response. If no
   response or an invalid response is received, Column will decline the transaction.

Note: all decisioning information is included in the `decisioning_details` struct in the Card Transaction Event.

### Webhook Setup

To enroll an endpoint to receive real-time decisioning events the existing webhook endpoints API can be used with
the specific event type of `decision.issuing.card_transaction`. Real-time decisioning events will have the same
`Column-Signature` header that can be used to validate the request originated from Column.

It is recommended to use a different endpoint for real-time decisioning that is optimized for latency since there is a
3-second deadline for responses.

The endpoint must return the real-time decision response shape, such as a `decision` value of `approve`, `decline`, or
`partially_approve`. Responses that do not include a recognized `decision` value are treated as invalid and Column will
decline the authorization. If you are using the local example webhook server, register the authorization route
`/webhooks/cards/authorizations` for this event type. This route is distinct from the token provisioning routes, such as
`/webhooks/cards/tokens`.

Note: if your system fails to respond to a real-time decisioning request, Column will not retry the request and decline
the authorization. Column also has a deadline to respond to the card networks, and it does not provide sufficient time for
retries. Column will send a webhook to notify you of the decline, and the `decision_reason` in `decisioning_details`
indicates what went wrong:

| Decision Reason ::min                     | Description                                                                                                                      |
| ----------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- |
| `realtime_authorization_endpoint_missing` | No webhook endpoint is registered for `decision.issuing.card_transaction`.                                                       |
| `realtime_authorization_request_timeout`  | Your endpoint did not respond within the deadline.                                                                               |
| `realtime_authorization_connection_error` | Column could not connect to your endpoint.                                                                                       |
| `realtime_authorization_invalid_response` | Your endpoint returned a response Column could not use, such as an unrecognized `decision` value or an invalid partial approval. |
| `error`                                   | Your endpoint returned a non-success HTTP status. The `decision_source` is `platform_owner`.                                     |

### Real-time Decision Object

The real-time decision object contains the fields `card_transaction`, `proposed_event`, and, when Column has computed the
card account's balance, `available_balance`. If the decision relates to a new transaction, the transaction and proposed
event will both be created after the response is returned. If the decision relates to an existing event (for example, the
request is for an incremental auth), the `card_transaction` will contain the existing card transaction, and the proposed
event will be appended to the existing transaction.

## 3DS Authentication Decisioning

You can also make real-time decisions during 3DS authentication, before a challenge is shown. Subscribe a webhook endpoint
to `decision.issuing.card_authentication`. Column sends the
[3DS authentication decision request](/api/card-real-time-decisioning/3ds-authentication-decision-request-object) to that
endpoint with the authentication attempt and available network context. Return a
[3DS authentication decision response](/api/card-real-time-decisioning/3ds-authentication-decision-response-object) with
one of these decisions:

- `frictionless_approve` recommends that the network's risk system authenticate without a cardholder challenge.
- `challenge` proceeds to a cardholder challenge.
- `decline_authentication` rejects the authentication. You may return `decline_reason` as `suspected_fraud` or
  `transaction_not_permitted`; Column defaults to `suspected_fraud` when the reason is omitted.

Column waits up to 1 second for a valid response. A timeout, connection error, non-success response, or invalid response
fails safe to `challenge`. This differs from card authorization decisioning, which waits up to 3 seconds and declines when
your endpoint does not return a valid decision. Column does not retry either decision request within the network deadline.

`frictionless_approve` is a recommendation to the network's risk system and might not produce a frictionless result in
every flow. A `challenge` decision fails authentication if the cardholder has no supported challenge method, such as an
email address on the person entity. Data-only authentications with merchant challenge indicator `06` do not invoke your
decision endpoint.

### Sandbox Testing

Call `POST /simulate/issuing/cards/:card_id/threeds/challenge` in sandbox. Set `realtime_decision` to exercise a specific
decision without calling your endpoint, and optionally set `decline_reason` for a declined authentication. Omit
`realtime_decision` to invoke a sandbox endpoint subscribed to `decision.issuing.card_authentication`. If no subscribed
endpoint exists, the simulator preserves its default behavior and creates an OTP challenge.

### Decline Reasons

If you decide to decline a transaction, you can optionally specify a `decline_reason` to provide more information to the
merchant who originated the request. Generally, it is best practice and more user-friendly for cardholders to include a
reason for a decline. Additionally, some card networks assess additional fees if general decline codes are used.

If a reason isn't specified in the real-time decision response, Column will return a generic "do not honor" response code.

### Partial Approvals

Some card networks and merchants support partial approvals. This allows your platform to approve a subset of the requested
amount. An example of this is if a debit card had a remaining balance of $10 but is used to purchase a $50 item. If you
opt to partially approve $10, the merchant will apply $10 and then request an alternate form of payment for the remaining
$40.

In the real-time decisioning request, the field `can_support_partial_approvals` field indicates whether the merchant supports
partial approvals. You can then return the decision choice of `partially_approve` with an amount set in `partially_approve_amount`.
If your system returns `partially_approve` when it is unsupported, without an amount, with a zero amount, or with an amount
greater than the requested amount, Column will decline the transaction with the `realtime_authorization_invalid_response`
reason. A `partially_approve` response with an amount equal to the requested amount is recorded as a partial approval of
the full amount.

Partial approvals are not supported for incremental authorizations or reauthorizations. Column declines a
`partially_approve` response to those requests with the `realtime_authorization_invalid_response` reason.

For automated fuel dispenser transactions that support partial approvals, if the card account's available balance is lower
than the requested amount, Column limits the proposed event to the available balance before sending the real-time decision
request instead of declining for insufficient funds. Respond with `partially_approve` (or `decline`) in this case; an
`approve` response is declined with the `realtime_authorization_invalid_response` reason.
