Skip to main content

Rest API

Stitch provides an alternative REST interface to create payment requests for different payment methods. View the relevant guide for complete information on each payment method integration, including handling interaction URLs/redirects and webhooks.

Integration Overview

Follow the steps described in the client token guide to obtain a client token with the client_paymentrequest scope.

Use the Stitch REST API URL https://api.stitch.money/v2 for all requests on test and live clients. Standard HTTP status conventions are used for all API responses.

Payment Request Creation

A POST request is used to create a payment request for one or more payment methods. The payment request allows you to specify the amount, merchant details, payer information, and any other relevant references. The paymentMethods object indicates which payment methods are enabled and includes any method-specific information required to process the payment

The payer object should be specified with stored information on the payer. The provided information is used to increase the efficacy of fraud risk checks done by Stitch. At a minimum, the identifier should always be specified within a request.

Initiate a POST request to create a token with the following request body:

curl -X POST 'https://api.stitch.money/v2/payment-requests' \
-H 'Content-Type: application/json' \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-d '{
"amount": {
"currency": "ZAR",
"quantity": 1
},
"externalReference": "TestPayment",
"expireAt": "2026-12-31T00:00:00Z",
"payer": {
"identifier": "PAYER-001",
"identifyingDocument": {
"type": "identity_document",
"country": "ZA",
"number": "0401016727083"
},
"mobileNumber": "0711234567",
"email": "hello@stitch.money",
"fullName": "Lilo Pelekai"
},
"metadata": {
"deliveryMethod": "delivery"
},
"paymentMethods": {
"eft": {
"enabled": true,
"payerReference": "PayerRef",
"beneficiaryReference": "Stitch",
"beneficiary": {
"name": "Lilo",
"bank": "absa",
"accountNumber": "123456789"
},
"capitecPay": {
"enabled": true
},
"absaEft": {
"enabled": true
}
},
"card": {
"enabled": true
},
"crypto": {
"enabled": false
}
}
}'
FieldTypeDescription
amount.currencystringThe payment request currency. Possible values: ZAR
amount.quantitynumericThe payment request value.
merchantIdstring (optional)The Stitch resource identifier of a pre-registered sub-merchant on your client. When supplied, the payment is routed and settled against the merchant's configuration. Mutually exclusive with paymentMethods.eft.beneficiary — supply one or the other, not both.
externalReferencestring (optional)A custom unique identifier associated with the request
expireAtstringAn ISO 8601 date that defines the expiration for the request
restrictPayerBankstring (optional)Restricts the payer to a single bank when paying via Pay by Bank. When set, the payer can only pay from the specified bank. Must be a valid PayerBankId value.
paymentMethodsobjectAn object specifying the payment methods enabled and their configuration.
metadataobjectUsed for additional metadata relating to the request. Nested objects must be stringified JSON objects.
splitSettlementsarray (optional)Split payment instructions for an individual transaction or batch collection. See the integration guide for full field reference.

Specifying a Merchant

The merchantId field is an optional Stitch-supplied merchant identifier that routes the payment to a pre-registered merchant on your client. This is typically used in multi-merchant configurations (e.g. marketplaces or aggregator integrations), where funds for the payment should be associated with a specific sub-merchant or registered entity rather than the default merchant configured on your client.

When supplied, the value must reference a merchant that has been pre-provisioned by Stitch against your client. An example value is shown below:

bWVyY2hhbnQvNzhjMzc2NjUtZTgyNi00MGEyLWJiZDUtOTQ1YWNlYjYzMTc1
Provisioning Merchants

The merchantId value is a Stitch resource identifier (not your acquirer-assigned MID). Each pre-registered merchant may be configured for a different subset of payment methods. Requirements per merchant will be aligned with you during onboarding.

Payer Information Fields

FieldTypeDescription
identifierstring (optional)The client's internal identifier for the payer.
identifyingDocumentobject (optional)The payer's identification document. Required for Capitec Pay Verified Flow.
identifyingDocument.typestring (optional)Type of identifying document. Possible values: identity_document, passport, temporary_residence.
identifyingDocument.countrystring (optional)The country code of the document (e.g., ZA).
identifyingDocument.numberstring (optional)The document number.
mobileNumberstring (optional)The payer's contact number.
emailstring (optional)The payer's email address.
fullNamestring (optional)The payer's full name.
accountCreatedDatestring (optional)The ISO date when the payer's account was created with the client.

Payment Method Fields

Enabled Payment Methods

Note that Pay by Bank is enabled on payment requests by default. Set paymentMethods.eft.enabled to false to create a payment request without Pay by Bank enabled. Capitec Pay and ABSA Pay require that eft is enabled and must be explicitly enabled.

eft Fields

FieldTypeDescription
eftobject (optional)Pay by Bank payment method configuration. Enabled by default.
eft.enabledboolean (optional)Whether Pay by Bank is enabled. Defaults to true.
eft.payerReferencestring (optional)The payer's bank statement reference. Required for Pay by Bank.
eft.beneficiaryReferencestring (optional)The beneficiary's bank statement reference.
eft.beneficiaryobject (optional)The beneficiary's destination account. Required for Pay by Bank when merchantId is not supplied at the top level of the request. Mutually exclusive with merchantId — supply one or the other, not both.
eft.beneficiary.namestringThe account holder's name.
eft.beneficiary.bankstringThe beneficiary’s bank. Must be a valid BankBeneficiaryBankId value.
eft.beneficiary.accountNumberstringThe beneficiary's account number.
eft.capitecPayobject (optional)Configuration for Capitec Pay (when supported).
eft.capitecPay.enabledboolean (optional)Whether Capitec Pay is enabled. Defaults to false.
eft.absaEftobject (optional)Configuration for ABSA Pay (when supported).
eft.absaEft.enabledboolean (optional)Whether ABSA Pay is enabled. Defaults to false.

card Fields

FieldTypeDescription
cardobject (optional)Card payment method configuration.
card.enabledboolean (optional)Whether card payments are enabled. Defaults to false.

crypto Fields

FieldTypeDescription
cryptoobject (optional)Cryptocurrency payment method configuration.
crypto.enabledboolean (optional)Whether crypto payments are enabled. Defaults to false.

The response includes the payment request id, status and relevant request information.

{
"id": "cGF5cmVxLzNiOTU1MDYwLWJkMTAtNGI1Mi05ZGMyLTg1OTE3OWJkMDIwOA==",
"amount": {
"currency": "ZAR",
"quantity": 1
},
"externalReference": "TestPayment",
"expireAt": "2025-12-31T00:00:00",
"status": "pending",
"interaction": {
"type": "redirect",
"url": "https://secure.stitch.money/connect/payment-request/3b955060-bd10-4b52-9dc2-859179bd0208"
}
}

Restricting the Payer's Bank

Set the optional top-level restrictPayerBank field to limit Pay by Bank to a single bank — the payer will only be able to pay from the specified bank. It must be a valid PayerBankId value. Note that this does not affect other payment methods that may be enabled on the payment request.

The example below restricts the payer to Capitec.

curl -X POST 'https://api.stitch.money/v2/payment-requests' \
-H 'Content-Type: application/json' \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-d '{
"amount": {
"currency": "ZAR",
"quantity": 1
},
"externalReference": "TestPayment",
"expireAt": "2026-12-31T00:00:00Z",
"restrictPayerBank": "capitec",
"payer": {
"identifier": "PAYER-001",
"identifyingDocument": {
"type": "identity_document",
"country": "ZA",
"number": "0401016727083"
},
"mobileNumber": "0711234567",
"email": "hello@stitch.money",
"fullName": "Lilo Pelekai"
},
"metadata": {
"deliveryMethod": "delivery"
},
"paymentMethods": {
"eft": {
"enabled": true,
"payerReference": "PayerRef",
"beneficiaryReference": "Stitch",
"beneficiary": {
"name": "Lilo",
"bank": "absa",
"accountNumber": "123456789"
},
"capitecPay": {
"enabled": true
},
"absaEft": {
"enabled": true
}
}
}
}'

Surface URL and Handle Callback

The URL returned by the API needs a redirect_uri on an allowlisted domain, appended as a query string parameter. Send your customer to that URL and they'll be guided through the payment request. Test clients have these domains allowlisted by default:

The allowlist covers whole domains, so any path on an allowlisted domain works. If https://example.com is on your allowlist, then https://example.com/payment is a valid redirect_uri, and the full URL you expose to your customer looks like this:

https://secure.stitch.money/connect/payment-request/2b068bd5-6a5a-42e1-8a45-673cb3ede612?
redirect_uri=https%3A%2F%2Fexample.com%2Fpayment
Allowlisting redirect domains

To add or remove a domain, reach out to the Stitch team.

Production clients can't use an insecure (http) redirect_uri:

http://example.com/payment

https://example.com/payment

Once your customer completes or cancels the payment request, they're redirected back to the redirect_uri with these query string parameters:

FieldDescriptionType
idThe unique Stitch ID of this payment request.ID
statuscomplete if the payment request was completed successfully, closed if the customer closed the UI, or failed if something went wrong.String
externalReferenceThe value you supplied in the externalReference field when creating the payment request. Use it to match the payment request against your own records.String

Use the id to retrieve the final payment request status from the Stitch API, and to match against incoming webhooks.

danger

Don't use status for database operations — anyone can tamper with a query string parameter. To protect yourself from a fake payload sent to your redirect or webhook endpoint:

  1. Treat webhooks as your source of truth. They're always sent by Stitch.
  2. Use signed webhooks, so you can verify the signature on every incoming payload.

Webhooks also mean you still learn the final status of a payment request if the redirect never arrives — for example, if the request times out.

Alternative Redirect URI on Failure

Optionally, you can append a failure_redirect_uri to the URL returned from the API — e.g. ?redirect_uri=https%3A%2F%2Fexample.com%2Fpayment&failure_redirect_uri=https%3A%2F%2Fexample.com%2Fpayment%2Ffailure.

If this parameter is supplied, users will only be redirected to the redirect_uri when the status is complete, and to the failure_redirect_uri when the status is closed or failed. In other words, users that successfully complete a payment are directed to the redirect_uri, and those that exit without completing a payment are directed to the failure_redirect_uri.

The failure_redirect_uri receives the same query parameters and is subject to the same validations as the redirect_uri, including requiring the secure https:// protocol for production clients, and being validated against the configured redirect URI whitelist for your client.

Using Multiple Internal Redirect URIs

failure_redirect_uri only splits two ways. For anything finer-grained, branch on status yourself.

If different outcomes should land your customer on different pages, keep a single allowlisted redirect domain and branch to your internal URLs from there. An example is shown below, in NodeJS:

const status = params.status;

switch (status) {
case "complete":
redirect("/success");
break;
case "closed":
case "failed":
redirect("/retry");
break;
default:
break;
}

Payment Request Expiry

It is highly recommended that an expireAt field is supplied in the request body. At the specified date and time, the payment request status will automatically transition to state expired if the payment request is not yet completed.

Payment Request Statuses

The table below describes the different statuses for a payment request. A payment request is created with status pending.

StatusDescription
completedThe user has completed the payment and is a final state.
pendingThe user hasn't yet completed the payment initiation request, or they exited Stitch SafeLink before fulfilling the payment.
cancelledThe payment request was manually cancelled by the client.
expiredThe payment request has expired while awaiting user interaction.

Retrieving Payment Request Status

Initiate a GET request to retrieve a specific request by ID:

curl -X GET 'https://api.stitch.money/v2/payment-requests/cGF5cmVxLzNiOTU1MDYwLWJkMTAtNGI1Mi05ZGMyLTg1OTE3OWJkMDIwOA==' \
-H 'Content-Type: application/json' \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \

The response object is identical in structure to the one returned by the POST request used to create a payment request.

{
"id": "cGF5cmVxLzNiOTU1MDYwLWJkMTAtNGI1Mi05ZGMyLTg1OTE3OWJkMDIwOA==",
"amount": {
"currency": "ZAR",
"quantity": 1
},
"externalReference": "TestPayment",
"expireAt": "2025-12-31T00:00:00",
"merchantId": "bWVyY2hhbnQvNzhjMzc2NjUtZTgyNi00MGEyLWJiZDUtOTQ1YWNlYjYzMTc1",
"status": "completed"
}

The merchantId is the same base64-encoded value supplied on the create request — see Specifying a Merchant. If the payment request was created without a merchantId, the field is omitted from the response.

Payment Request Cancellation

Payment requests that are not completed or expired i.e. in a terminal state can be cancelled before fulfilment. Cancelled payment requests are not processed nor can be processed and have a cancelled status. Note that a payment request with an in-flight transaction cannot be cancelled.

Initiate a POST request to cancel a payment request. The payment request id is passed as a path parameter, and the cancellation reason in the request body:

curl -X POST 'https://api.stitch.money/v2/payment-requests/cGF5cmVxLzNiOTU1MDYwLWJkMTAtNGI1Mi05ZGMyLTg1OTE3OWJkMDIwOA==/cancel' \
-H 'Content-Type: application/json' \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-d '{
"reason": "duplicate_payment"
}'
FieldLocationTypeDescription
idpathstringThe unique Stitch ID
reasonbodystringThe cancellation reason

The response includes the id of the payment request with status code 200 OK if cancellation is successful. Standard HTTP response codes are returned for non-success scenarios.

{
"id": "cGF5cmVxLzNiOTU1MDYwLWJkMTAtNGI1Mi05ZGMyLTg1OTE3OWJkMDIwOA=="
}
Automatic cancellation

Optionally, when the user clicks the X on the dialog box, the payment initiation request can be automatically cancelled instead. This will subsequently invoke the status update, and corresponding webhook notification.

If you would like this feature enabled on your client, reach out to the Stitch team to have it configured.

Error Handling

Error handling is communicated through standard HTTP status codes. Each response includes a clear status and message, helping you identify the issue and take the appropriate next steps.

Stitch returns an error response with the following format if a body is applicable for the status code, e.g. 400 BAD REQUEST

{
"title": "Bad Request",
"code": "BAD_USER_INPUT",
"detail": "Invalid beneficiary reference"
}

HTTP Status Codes

Status CodeMeaningDescription
200OKThe request was successful. The response body contains the payment request resource.
201CreatedThe payment request was successfully created. The response body contains the new payment request resource.
400Bad RequestThe request was invalid. For example, a required field is missing or malformed.
401UnauthorizedAuthentication failed or no valid authentication credentials provided.
403ForbiddenThe authenticated user does not have permission to perform this action.
404Not FoundThe requested resource (e.g., disbursement) was not found.
409ConflictThere is a duplicate nonce or other conflict with the request.
429Too Many RequestsToo many requests have been made in a short period (rate limiting).
500Internal Server ErrorAn unexpected error occurred on the Stitch platform.