Managing transactions

Authorize transactions, and process recurring payments. An overview of the Transactions API.

A unified transaction lifecycle

Primer's Transaction API enables you to process and manage payments across all processors and payment methods, through a unified transaction lifecycle. This guide assumes you have read our Quick start guide.

Transaction lifecycle


Transactions will go through a series of statuses when progressing from authorization to final settlement.
StatusDescription
Pending
An authorization request has been received and submitted to the processor, but is yet to reach "Authorized" status. This typically occurs for asynchronous processors, such as Direct Debit providers.
Authorized
The transaction has been authorized by the processor and can proceed to capture. This status occurs when performing authorization-only requests.

Merchants will typically fulfil orders at this stage.
Declined
This transaction was declined by the processor, either at a gateway or acquirer level. See the reason object in your response payload for more details.
Settling
Funds have been captured and are due to be settled to your designated bank account for this processor and merchant ID.

Merchants will typically fulfil orders at this stage.
Cancelled
The transaction has been cancelled. Typically this involves us sending a "void" request to the processor.
Partially Settled
Funds have been partially captured for this transaction and will soon be settled to your bank account. Not all processors support partial capture.
Settled
Funds have been settled to your bank account. Typically, no further actions will be taken.

Response payloads

For transaction lifecycle requests, Primer will respond with a 200 provided the request was successfully processed. The response will contain the following attributes:

AttributesDescription
successtrue indicates that your intended request was successful.

e.g. if you sent a cancellation request and the transaction was successfully cancelled, this attribute would be set to true.
reasonIf the event has been unsuccessful, a payload describing the problem.
transactionThe Transaction object, representing the current state of the transaction. This contains Primer's unique transaction ID which you will use for subsequent transaction lifecycle requests.

An example transaction lifecycle response:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
{
"success": false,
"reason": {
"decisionType": "APPLICATION_ERROR", // null if success equals true
"declineReason": "...", // null if decisionType is not equal to ISSUER_DECLINED
"message": "This request could not be honored because..."
"source": "BRAINTREE"
},
"transaction": {
"createdAt": "2020-09-26T14:24:15.540899",
"id": "9483a0c5-b1c3-42f5-ab73-d3feee09fb46",
"primerAccountId": "2ff302dc-45d7-4759-85fc-cc905e7d3191",
"merchantId": "<YOUR_MERCHANT_ID>",
"processorTransactionId": "8ftnw094",
"orderId": "order-123",
"status": "DECLINED",
"riskData": [
... // AVS, CVV and proprietary risk data
],
Show all 46 lines ↓
json

If Primer responds with a 4XX, there has been an API validation error, and the request has not been sent to the processor. In this case, the response payload will contain an error object with the following attributes:

AttributesDescription
errorIdThe error code returned from Primer indicating the reason for rejection.
descriptionA human readable description of the error.
diagnosticsIdA unique identifier of the request. Please quote this identifier when contacting your account manager.
validationErrorsA list of validation errors (if applicable).

An example error response:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
{
"error": {
"errorId": "RequestValidationError",
"description": "We were unable to validate your request, please check your payload against https://primer.io/docs/api",
"diagnosticsId": "11738938659721344025",
"validationErrors": [
{
"model": "BasicPaymentAPIRequest",
"errors": [
{
"path": "$.amount",
"description": "Missing required field"
}
]
}
]
}
}
json

Errors
For more on errors, see our API Reference.

Accepting payments

Our Transactions API supports idempotency by providing an optional Idempotency-Key header. Multiple requests to the same endpoint using the same idempotency key will be processed only once.

For example, if we successfully receive a request but the connection drops before you receive a response, you may automatically retry that request. Without the use of an idempotency key, we would process the request a second time. By supplying an idempotency key, we ensure that the retried request is not processed a second time.

This example demonstrates a valid, authenticated, idempotent request.

1
2
3
4
5
6
7
8
9
10
11
curl --location --request \
POST 'https://api.sandbox.primer.io/transactions/auth' \
--header 'X-Api-Key: <YOUR_API_KEY>' \
--header 'Idempotency-Key: order-123' \
--data '{
"paymentMethod": "token",
"orderId": "order-123",
"amount": 700,
"currencyCode": "EUR",
"merchantId": "<YOUR_MERCHANT_ID>"
}'
curl

Many payment methods support an auth and capture flow, where authorizing the transaction will put a hold on customer funds for a period of time (typically determined by the card scheme), and capturing will transfer funds from the customer's account to your acquirer - and bank account. Primer enables you to to perform authorization and capture requests separately, or at once.

Authorizing a payment

Primer sends an auth and capture request by default. If you want to authorize and capture separately then pass capture: false on the authorization request. Upon success, the transaction will transition to SETTLING or SETTLED (depending on the payment method type). For authorization-only requests, the transaction will transition to AUTHORIZED where it is ready for a capture or cancel request.

ParametersDescription
paymentMethodA one-time use token generated from our checkout libraries, or a recurring token retrieved from the Vault API. e.g. hXIHB_WfR2-M6PM13JDmQnwxNjAxMTE3NTA4. One-time use tokens expire after 15 minutes.
orderIdYour reference for the transaction.
amountThe amount you would like to charge the customer, in minor units. e.g. for $7, use 700.
currencyCodeThe 3 digit currency code in ISO 4217 format. e.g. use USD for US dollars.
merchantIdThe unique merchant ID associated with your processor. Learn how to retrieve your merchant ID.
vaultVault options to store payment methods (if supported).
Optional
unless vaulting
customerDetailsDetails about your customer. e.g. shipping, billing address.
Optional
unless vaulting.
captureWhether or not the transaction should be directly submitted for settlement upon succesful authorization. true by default, or specify false for authorization-only requests.
Optional

An example auth/capture request:

1
2
3
4
5
6
7
8
9
10
11
curl --location --request \
POST 'https://api.sandbox.primer.io/transactions/auth' \
--header 'X-Api-Key: <YOUR_API_KEY>' \
--header 'Idempotency-Key: order-123' \
--data '{
"paymentMethod": "token", # one-time use, or recurring token
"orderId": "order-123",
"amount": 700,
"currencyCode": "EUR",
"merchantId": "<YOUR_MERCHANT_ID>"
}'
curl

Recurring payments

Primer enables you to store payment method information in our unified vault, for recurring transactions (when the payment method supports it). This agnostic storage layer enables you to process transactions across different processors (typically for card payments).

To store a payment method on authorization, set the vault and customerDetails.customerId attributes in your request. This customerId is your reference for the customer, and is used to subsequently retrieve payment methods for a given customer.

Vault ParametersDescription
paymentMethodSet the value to ON_SUCCESS, this will vault your payment method if the authorization request was successful.
recurringCan be one of the following options:

SCHEDULED subsequent recurring payments on a fixed schedule and a set amount, merchant-initiated (e.g subscriptions).

SCHEDULED_FIRST the first in a series of recurring payments or subscription, customer-initiated.

ONE_TIME unscheduled payments that are not recurring on a predefined schedule or amount, merchant-initiated (e.g. balance top-up).
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
curl --location --request \
POST 'https://api.sandbox.primer.io/transactions/auth' \
--header 'X-Api-Key: <YOUR_API_KEY>' \
--header 'Idempotency-Key: order-123' \
--data '{
"paymentMethod": "token", # one-time use, or recurring token
"orderId": "order-123",
"amount": 700,
"currencyCode": "EUR",
"merchantId": "<YOUR_MERCHANT_ID>",
"vault": {
"paymentMethod": "ON_SUCCESS",
"recurring": "SCHEDULED",
},
"customerDetails": {
"customerId": "<YOUR_CUSTOMER_ID>"
}
}'
curl

Capture

If you have performed an authorization-only request, you can now fully capture, or partially capture funds from the authorization (depending on whether your selected processor supports it). The transaction will be updated to SETTLED or SETTLING (depending on the payment method type).

ParametersDescription
amountThe amount you would like to capture, in minor units. The authorized currency is assumed. e.g. for $7, use 700.
Optional
if no amount is specified it defaults to the full amount.
finalIndicates whether the capture request is the final capture request.
Optional
Defaults to true.
1
2
3
4
5
6
7
8
curl --location --request \
POST 'https://api.sandbox.primer.io/transactions/<primer-transaction-id>/capture' \
--header 'X-Api-Key: <YOUR_API_KEY>' \
--header 'Idempotency-Key: order-123' \
--data '{
"amount": 700,
"final": true
}'
curl

Managing Payments

Cancelling a payment

Provided the transaction has not reached SETTLED, Primer will typically send a "void" request to the processor, thereby cancelling the transaction and releasing the hold on customer funds. Upon success, the transaction will transition to CANCELLED.

Example cancellation request:

1
2
3
4
curl --location --request \
POST 'https://api.sandbox.primer.io/transactions/<YOUR-TRANSACTION-ID>/cancel' \
--header 'X-Api-Key: <YOUR_API_KEY>' \
--header 'Idempotency-Key: order-123' \
curl

Refunding payments

Refunds

By default, this request will refund the full amount. Optionally, pass in a lesser amount for a partial refund.

ParametersDescription
amountThe amount you would like to refund the customer, in minor units. e.g. for $7, use 700.
Optional
defaults to captured amount.
orderIdYour reference for the transaction.
Optional
by default this will be set to the authorization orderId.
1
2
3
4
5
6
7
8
curl --location --request \
POST 'https://api.sandbox.primer.io/transactions/<YOUR-TRANSACTION-ID>/refund' \
--header 'X-Api-Key: <YOUR_API_KEY>' \
--header 'Idempotency-Key: order-123' \
--data '{
"orderId": "order-123"
"amount": 100 # supply this parameter for a partial refund, otherwise defaults to full amount
}'
curl