Charges for Variable Payments
Once a consent has been successfully granted, it may be charged by initiating a transaction using the consent token. This will capture funds via the user's authorized Capitec Pay method, assuming initiation is within bounds of the granted consent terms.
Initiating a Transaction
The initiateTransaction
API mutation requires a client token with the scope transaction_initiate
. A valid consent request ID is required, and this consent request must be in a PaymentConsentGranted
state.
A typical initiateTransaction
API request for a Capitec Pay variable once-off consent will return a TransactionPending
status, with the final success or failure status to follow by webhook.
However, there are some scenarios in which a transaction initiation could fail immediately.
The GraphQL API URL https://api.stitch.money/graphql can be used for all transaction initiations (whether on test or live clients).
An example call is shown below:
To initiate charges with the initiateTransaction
endpoint, the following mutation input fields apply:
Field | Description | Type | Required |
---|---|---|---|
nonce | A unique value, that may only be used once to ensure the uniqueness of the consent request. | String | Yes |
externalReference | A reference field that you may supply, to associate to your transaction or order on your system. This also typically facilitates in reconciliation processes. | String | Optional |
beneficiaryAccountId | This is the unique identifier of the account that this transaction should be settled to. The account will be configured for your client, and Stitch will provide you with this unique identifier. | ID | Optional |
amount | The amount to be debited from the user, for this transaction attempt. | Money | Yes |
token | The consent request ID of the granted consent that is being charged. | ID | Yes |
paymentMethods.capitecPayRecurring.payerReference | This is the reference that will show up on the user's bank statement once funds are debited. | String | Yes |
paymentMethods.capitecPayRecurring.beneficiaryReference | This is the reference that will show up on your statement, once funds are received. This only applies if you are not being settled in batch, by Stitch. | String | Optional |
Variable Once-off Charge Limitations
If you are charging a granted ONCE_OFF
consent, there are a few limitations to be aware of:
- All charges must be made within 36 hours of the consent being granted.
- A maximum of 5 successful charges can be made on a variable once-off consent.
- To distinguish a tip charge from a standard charge, the
capitecPayRecurring.isTip
field may be set totrue
. - All charges, combined, must be less than or equal to the total amount, as specified in
paymentOptions.variable.max.amount
. This should be inclusive of any tip charges.
Transaction Statuses
The table below describes the different statuses a transaction can have:
Status | Description |
---|---|
TransactionPending | The transaction has been successfully initiated, and is processing. |
TransactionSuccess | The transaction has been successfully completed, and user's account has been charged. |
TransactionFailure | The transaction failed to be charged on the user's account. An associated reason will be returned with this status. |
Subscribe to Webhooks
Webhooks for transactions can be subscribed to by running the clientWebhookAdd
mutation, to receive transaction
webhook events.
Webhook Statuses
The transaction
webhook will be dispatched for each of the following status updates:
TransactionSuccess
TransactionFailure
Example Transaction Success Payload
{
"clientId": "test-950f1098-dacf-4105-9958-c2319ab1a0bb",
"data": {
"amount": {
"currency": "ZAR",
"quantity": "123"
},
"consentRequestId": "cGF5bWVudGNvbnNlbnRyZXF1ZXN0L2JkNDMyMGMxLTg5ZDktNDA1MC1iMDcyLWQ4MmNiZTk4ZTA4Ng==",
"createdAt": "2025-07-03T14:57:27.900Z",
"externalReference": "my-transaction-ref-2",
"id": "Y2FwaXRlY3BheXJlY3VycmluZ3RyYW5zYWN0aW9uL2ZmMDg5OTQxLTY4ODMtNDEzNS04ZTFjLWZlYjVmM2Y4NDNlNw==",
"nonce": "my-transaction-nonce-2",
"status": "SUCCESS",
"statusReason": null,
"type": "CAPITEC_PAY_RECURRING",
"updatedAt": "2025-07-03T14:57:29.065Z"
},
"datetime": "2025-07-03T14:57:29.074Z",
"id": "transaction:status:SUCCESS:ff089941-6883-4135-8e1c-feb5f3f843e7",
"type": "transaction"
}
Example Transaction Failure Payload
{
"clientId": "test-950f1098-dacf-4105-9958-c2319ab1a0bb",
"data": {
"amount": {
"currency": "ZAR",
"quantity": "123"
},
"consentRequestId": "cGF5bWVudGNvbnNlbnRyZXF1ZXN0L2JkNDMyMGMxLTg5ZDktNDA1MC1iMDcyLWQ4MmNiZTk4ZTA4Ng==",
"createdAt": "2025-07-03T15:04:50.457Z",
"externalReference": "my-transaction-ref-41",
"id": "Y2FwaXRlY3BheXJlY3VycmluZ3RyYW5zYWN0aW9uLzA0ODFjOTcyLTJkODQtNDhhYy04YzRmLTBhNjU5ZmRmMDIxYg==",
"nonce": "my-transaction-nonce-41",
"status": "FAILURE",
"statusReason": "capitecInsufficientFunds",
"type": "CAPITEC_PAY_RECURRING",
"updatedAt": "2025-07-03T15:04:50.528Z"
},
"datetime": "2025-07-03T15:04:50.553Z",
"id": "transaction:status:FAILURE:0481c972-2d84-48ac-8c4f-0a659fdf021b",
"type": "transaction"
}
Testing and Simulation
When using a test client, transaction initiation scenarios can be simulated by configuring the beneficiaryReference
field when initiating the transaction.
The state returned by the Stitch API is TransactionPending
, with the final transaction success or failure state sent by webhook.
However, there are some scenarios in which a transaction could fail immediately.
Transaction failure reasons can be simulated by modifying the beneficiaryReference
field, and setting it to the corresponding reason.
beneficiaryReference input value | Result state.__typename | Result state.reason |
---|---|---|
clientDeactivated | TransactionFailure | capitecClientDeactivated |
clientBlockedMerchant | TransactionFailure | capitecClientBlockedMerchant |
transactionLimitExceeded | TransactionFailure | capitecTransactionLimitExceeded |
consentRevoked | TransactionFailure | capitecConsentRevoked |
invalidAmount | TransactionFailure | capitecInvalidAmount |
consentInvalid | TransactionFailure | capitecConsentInvalid |
insufficientFunds | TransactionFailure | capitecInsufficientFunds |
internalServerError | TransactionFailure | internalServerError |