api/version-1.md

Version 1

TopCharge API Documentation version 1

This is a comprehensive documentation for integrating TopCharge API into your services.

At TopCharge, we focus on easy integration for merchants and on providing everything they need through a few APIs and limited workflows.

Since you are going to implement TopCharge API version 1 in your system, it is expected that you have access to the TopCharge merchant panel for creating credentials. After generating the credentials pair, including api key and api secret, you will be able to call all the APIs listed in the following documentation.

api key and api secret should be kept safe in your secret manager. They are static credentials, and if they are leaked, they can cause problems for your account.

Use api.topcharge.dev as base URL

Authentication

For every request, we expect the api key to be included in the HTTP request headers, set as x-api-key.

Payment creation flow

A payment in TC is an entity that merchants can create to provide a fast, secure, and reliable method for their customers to pay their settlements in a convenient way.

Your services should correctly implement TC's payment flow as described below:

  • Call the create payment API
  • Wait for your customer to complete the payment
  • If the payment is successful, the customer will be redirected to the provided redirectUrl from the previous step
  • Our service will call your back-end using the provided callbackUrl from the previous step

You can cancel the payment for any reason if it is not paid yet. We ensure the consistency of both your and your customers’ funds in our system.

In addition, all created payments have a 30-minute payment window. After that, we automatically cancel the payment and inform your back-end service using the provided callback URL.

You can rely on our webhook service to receive the latest payment status updates; however, you can also check payment statuses using the get status API.

Create payment

POST HTTP Request
/api/v1/payment

Creates a new payment.
You should send your payment data in the request body, serialized as JSON:

  • paymentAmount (required): Amount in IQD
  • description (optional): Short description, we show your text to your customer in checkout page. Be sure that is less than 128 characters.
  • redirectUrl (optional): After successful payment, the customer will be redirected to this URL
  • callbackUrl (optional): This URL will be called for every change in payment status (your back-end service endpoint)

On successful payment creation, you will receive a 201 status code with the following response data:

  • paymentId (string): A unique 26-character identifier
  • paymentUrl (string): Checkout payment URL
  • paymentAmount (string)
  • status (enum-string): Payment status (PENDING, PAID, EXPIRED, CANCELLED)
  • expiresAt (date-string): ISO-formatted date string showing the payment expiration time
  • createdAt (date-string): ISO-formatted date string showing the payment creation date and time

Get payment status

GET HTTP Request
/api/v1/payment/status/{{paymentId}}

Returns payment data, including the payment status.

On successful lookup, you will receive a 200 status code with the following response data:

  • paymentId (string): A unique 26-character identifier
  • paymentAmount (string)
  • status (enum-string): Payment status (PENDING, PAID, EXPIRED, CANCELLED)
  • expiresAt (date-string): ISO-formatted date string showing the payment expiration time
  • paidAt (date-string or null): If the customer pays, this field contains an ISO-formatted date string representing the payment time; otherwise, it is null
  • createdAt (date-string): ISO-formatted date string showing the payment creation date and time

Cancel payment

POST HTTP Request
/api/v1/payment/cancel/{{paymentId}}

Cancels PENDING payments.

Returns a 201 status code on success.

If you try to cancel a non-pending payment, no error will be thrown and the cancellation process will be skipped.

Accounting

Verify credentials

GET HTTP Request
/api/v1/account/verify-credentials

Returns a 200 status code if your credentials are correct and active; otherwise, an error status code is returned.

Balance

GET HTTP Request
/api/v1/account/balance

Returns the merchant’s account balance:

  • totalBalance (string): Total assets, including available and reserved funds
  • reservedBalance (string): Total amount of funds reserved for withdrawals or internal system transactions
  • availableBalance (string): Total available balance

Health check

Healthy

GET HTTP Request
/api/v1/healthy

You can use this API to check the status of our services. If it returns 200, everything is operating normally on our side.

Webhook

We do our best to update your services with near real-time data by notifying your system through the provided callbackUrl. We expect you to expose an endpoint that listens for a POST HTTP request at the URL you specify in the create payment API.

If your API returns a successful status code such as 200 or 201, we mark the change log as received in our systems and no further calls will be triggered. If we receive any other status code, or if the request times out, we treat it as a failed attempt and retry in the next few seconds. We attempt to reach your service multiple times in case of failure; after that, we stop triggering the callback URL for the specific payment.

Our webhook payload schema looks like this:

  • paymentId (string): A unique 26-character identifier
  • paymentAmount (string)
  • status (enum-string): Payment status (PENDING, PAID, EXPIRED, CANCELLED)
  • expiresAt (date-string): ISO-formatted date string showing the payment expiration time
  • paidAt (date-string or null): If the customer pays, this field contains an ISO-formatted date string representing the payment time; otherwise, it is null
  • createdAt (date-string): ISO-formatted date string showing the payment creation date and time

Webhook payload verification

You should verify every webhook call using the x-tc-signature header in the following way:

  • Sort the payload in the request body by keys in ascending order and convert it into a JSON string (without spaces)
  • Sign the resulting string using your api secret with HMAC and SHA-512
  • Compare the generated signature with x-tc-signature; if they match, the request is valid, otherwise reject it