Skip to main content

Authorization Requests

Unit allows you to inject yourself into the decision making process, whenever a card gets used to move funds. Unit will make a call to a dedicated endpoint you create, letting you know about every attempt to use the card, and the details of the attempt. You will respond with an approval or a decline, based on your internal business logic. We refer to this process as "programmatic authorization of card use".

This capability can be used to:

  • Restrict payments to certain types of institutions / services
  • Create elaborate spend controls
  • Run your own fraud logic
  • Move funds between accounts of the customer in real time to prevent a card decline due to insufficient funds.

Programmatic authorization of card use

Note

The programmatic authorization feature is not enabled by default. To set it up, please reach out to your Unit contact.

You would have to create a dedicated API endpoint (details below) that Unit will call with every authorization request. You can configure that URL in the Unit Dashboard, in the org settings screen.

There are 3 types of card use that you can choose to receive authorization requests on: Purchases, ATM transactions, and Card Transactions (representing mostly peer-to-peer transfers). For each of those, you can choose whether to enable the programmatic authorization flow, as well as the default behavior in cases of timeout.

The Programmatic authorization of card use includes the following steps:

  1. An authorization pending http request is sent by Unit to the url you defined in your org settings.
  2. You can then approve or decline the authorization request by responding to the API call Unit sent to you.
  3. If you do not approve or decline the authorization request within 2 seconds, Unit will approve or decline it according to the default that is defined for you on Unit's settings (which can be changed any time by contacting Unit).
  4. The response from the approve operation will include the final authorization request status. Approving an authorization request may still result in a Declined status for different reasons. For example, at this stage Unit will check the balance on the account, and may decline the authorization due to insufficient funds.
  5. Unit will send an authorizationRequest.approved or authorizationRequest.declined webhook event based on the final approval status.
  6. If an authorization's amount changes the whole process will restart from stage (1).

Timeout Strategy Tags

When an authorization request is auto-completed using the timeout strategy (after the HTTP POST authorization flow times out or fails, or the webhook flow still leaves the request pending), Unit sets the outcome attribute on the authorization request resource. The following reserved tags are also persisted for backward compatibility:

TagValueDescription
decision_sourceprogrammatic_timeout_strategyIndicates the authorization was decided by the configured timeout strategy, not a manual approve/decline.
timeout_strategyApprove or DeclineIndicates which branch of the timeout strategy was applied.
Card Authorizations Flow
Note

To comply with Visa's network rules, you are required to support partial authorizations. When receiving a pending authorization request with the partialApprovalAllowed field set to true, and your business logic determines that the authorization should be approved but there are insufficient funds to cover the full amount, you must approve the authorization request and specify the partially approved amount in the amount field. The partially approved amount can be up to the available balance on the account.

Note

In order to test the programmatic authorization of card use in Sandbox, you may take advantage of the ability to simulate a Card Purchase Authorization Request, Card Transaction Authorization Request or ATM Authorization Request.

Understanding authorization decisions

When you use programmatic authorization of card use, two related questions come up on every card attempt:

  1. What did your integration produce? — Did your endpoint (or follow-up approve/decline call) explicitly approve or decline, time out, error, or never respond in time?
  2. Who actually drove the final card decision? — After Unit and the card network finish processing, was the resulting authorization or transaction driven by your decision, by Unit (for example insufficient funds or a timeout fallback), or by the network (for example issuer stand-in)?

Unit surfaces these on related resources so you can compare them and detect divergence — for example, a declined authorization request while an approved authorization still posts because the network stepped in.

QuestionWhere to read itREST attributeWebhook events
What your integration producedAuthorization Requestoutcome on purchase, ATM, and card transaction authorization request resourcesoutcome on authorizationRequest.*.approved and authorizationRequest.*.declined (not on .pending)
Who made the final card decisionAuthorization, Purchase, ATM, and Card transaction resourcescardDecisionSourcecardDecisionSource on authorization.created, authorization.declined, and transaction.created for purchase, ATM, and card transactions (not on other authorization webhook events)

Use the authorizationRequest relationship on an authorization or card transaction (when present) to connect the programmatic request to the resulting hold or posted transaction.

outcome values (authorization request; set when the programmatic flow reaches a terminal decision):

ValueDescription
ApprovedYour integration explicitly approved the request.
DeclinedYour integration explicitly declined the request.
PostTimeoutThe HTTP POST to your authorization endpoint timed out.
PostErrorThe HTTP POST to your authorization endpoint failed (non-timeout error).
WaitTimeoutYour integration did not call approve or decline in time.

cardDecisionSource values (authorization and card transaction; who had the final say on the card decision):

ValueDescription
OrgYour programmatic integration made the final decision.
UnitUnit made the final decision (for example insufficient funds after you approved).
NetworkThe card network advice path (excluding issuer stand-in).
TimeoutApproveDeposit-product timeout strategy approved the request.
TimeoutDeclineDeposit-product timeout strategy declined the request.
DefaultApproveDeposit-product auto-complete fallback approved the request.
InternalErrorInternal error fallback path.
IssuerStandInVisa issuer stand-in advice.

Both attributes are optional and may be absent on older records.

On authorization webhooks, cardDecisionSource is included only when the hold is created or declined (authorization.created and authorization.declined). It is not sent on authorization.canceled, authorization.updated, or authorization.amountChanged; use the Authorization resource (for example via webhook included) if you need the value on those lifecycle events.

Detecting divergence: Compare authorization request outcome and status with authorization status and cardDecisionSource. When they differ, cardDecisionSource indicates who overrode your integration. declineReason and declinedBy describe business decline detail; they do not replace cardDecisionSource.

ScenarioAuthorization request outcomeAuthorization statuscardDecisionSource
Normal approveApprovedAuthorizedOrg
Org declineDeclinedDeclinedOrg
Org approved, insufficient fundsApprovedDeclinedUnit
HTTP POST timeout, auto-declinePostTimeoutDeclinedTimeoutDecline
Org declined, network stand-inDeclinedAuthorizedIssuerStandIn
Ready-to-launch

The ready-to-launch transaction.created webhook payload does not include cardDecisionSource. Only the standard API webhook payload includes it for card-related transactions.

Securing your http servers

Ensure your server is only receiving the expected Unit requests.

Once your server is configured to receive payloads, it'll listen for any payloads sent to the endpoint you configured.

For security reasons, you probably want to verify that the payloads are coming from Unit.

To verify the payloads when defining a url you can set up a secret token which Unit will use to sign the payloads.

Setting up your secret token

You'll need to set up your secret token in two places: Unit dashboard and your server. To set your token in Unit Dashboard:

  1. Navigate to OrgSettings on the top menu under Developer section.
  2. Navigate to GeneralSettings under OrgSettings
  3. Enable API based authorization requests and set your url
  4. Enable Add optional secret and set your secret token

Verifying payloads from Unit

If your secret token is set, Unit will use it to create a hash signature with the entire body of the webhook request.

This hash signature, encoded with base64 is passed along with each request in the headers as X-Unit-Signature.

Unit uses an HMAC SHA1 to compute the hash.

Example of a NodeJS server verifying webhook payload
const express = require('express')
var crypto = require('crypto')
const app = express()
const port = 4000

app.post('/my-webhook', (request, response) => {
response.send('request passed signature validation...')
})

app.use(express.json());
app.use(express.urlencoded({
extended: true
}));

app.use((request, response, next) => {
var signature = request.header("x-unit-signature")
var hmac = crypto.createHmac('sha1', <your secret>)
hmac.update(JSON.stringify(request.body))

if(hmac.digest('base64') == signature) {
const responseBody = {
data: {
type: 'declineAuthorizationRequest',
attributes: {
reason: "InsufficientFunds"
},
},
};

response.status(200).json(responseBody);
}
else {
response.status(500).send("Signatures didn't match!")
}
})


app.listen(port, (err) => {
console.log(`server is listening on ${port}`)
})