Authentication
Toman uses OAuth 2.0 to authorize API requests. We will provide you with the required Username, Password, Client ID, and Client Secret required for the process of token acquirement.
Each endpoint in our project has none, one, or more scope requirements, which can be found in the endpoint documentation. Note that you have to had included the required scopes in your authentication process in order to be allowed to use them.
The authentication process URL for our staging and productions servers are:
Environment | Auth URL |
---|---|
Production | https://accounts.qbitpay.org/oauth2/token/ |
Staging | https://auth.qbitpay.org/oauth2/token/ |
The acquired token should be included among request headers with the prefix Bearer
:
Authorization: Bearer 5OGgq1FQS7jPITItICRwlDYZv5P91A
Get Access Token
To acquire your access token, you need to send your username
, password
, client_id
, and client_secret
to the auth
endpoint.
Request Data Example (Without Basic Authentication)
Sample Code (Without Basic Authentication)
import requests
auth_url = "https://auth.qbitpay.org/oauth2/token/"
username = "MY_USERNAME"
password = "MY_PASSWORD"
client_id = "MY_CLIENT_ID"
client_secret = "MY_CLIENT_SECRET"
response = requests.request(
"POST",
auth_url,
data={
"client_id": client_id,
"client_secret": client_secret,
"username": username,
"password": password,
"grant_type": "password",
"scope": "settlement.wallet.retrieve"
},
)
token = response.json()["access_token"]
refresh_token = response.json()["refresh_token"]
authorization_header = {
"Authorization": f"Bearer {token}"
}
endpoint_response = requests.request(
"GET",
"https://settlement-staging.qbitpay.org/wallets/deposits/summary/",
headers=authorization_header
)
print(endpoint_response.json())
curl -X POST -d "username=$USERNAME" \
-d "password=$PASSWORD" \
-d "client_id=$CLIENT_ID" \
-d "client_secret=$CLIENT_SECRET" \
-d "grant_type=password" \
-d "scope=settlement.wallet.retrieve" \
$AUTH_URL
curl -H "Authorization: Bearer $TOKEN" $API_ENDPOINT
POST /oauth2/token/ HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Host: auth.qbitpay.org
grant_type=password&
client_id=MY_CLIENT_ID&
client_secret=MY_CLIENT_SECRET&
username=MY_USERNAME&
password=MY_PASSWORD&
scope=settlement.single.submit%20settlement.single.verify
Request Data Example (Using Basic Authentication)
Sample Code (Using Basic Authentication)
import requests
auth_url = "https://auth.qbitpay.org/oauth2/token/"
username = "MY_USERNAME"
password = "MY_PASSWORD"
client_id = "MY_CLIENT_ID"
client_secret = "MY_CLIENT_SECRET"
response = requests.request(
"POST",
auth_url,
data={
"username": username,
"password": password,
"grant_type": "password",
"scope": "settlement.wallet.retrieve"
},
# this is how requests handles the basic http authentication
auth=(client_id, client_secret)
)
token = response.json()["access_token"]
refresh_token = response.json()["refresh_token"]
authorization_header = {
"Authorization": f"Bearer {token}"
}
endpoint_response = requests.request(
"GET",
"https://settlement-staging.qbitpay.org/wallets/deposits/summary/",
headers=authorization_header
)
print(endpoint_response.json())
curl -u $CLIENT_ID:$CLIENT_SECRET -X POST -d "username=$USERNAME" \
-d "password=$PASSWORD" \
-d "grant_type=password" \
-d "scope=settlement.wallet.retrieve" \
$AUTH_URL
curl -H "Authorization: Bearer $TOKEN" $API_ENDPOINT
POST /oauth2/token/ HTTP/1.1
Authorization: Basic TVlfQ0xJRU5UX0lEOk1ZX0NMSUVOVF9TRUNSRVRF
Content-Type: application/x-www-form-urlencoded
Host: auth.qbitpay.org
grant_type=password&
username=MY_USERNAME&
password=MY_PASSWORD&
scope=settlement.single.submit%20settlement.single.verify
Response Data Example
HTTP/1.1 200 OK
Content-Type: application/json
{
"access_token":"5OGgq1FQS7jPITItICRwlDYZv5P91A",
"expires_in":86400,
"token_type":"Bearer",
"scope":"settlement.single.submit settlement.single.verify",
"refresh_token":"upTFapSZfpJISYeo0YsZVjf8X29SBy"
}
Refresh Token
Since every access token has an expiration date (see expires_in
), you need to acquire a new
access token after it expires. The Oauth2 standard, is to
use refresh tokens.
To refresh your access token, you need to send your refresh_token
, client_id
, and client_secret
to the auth
endpoint with grant_type=refresh_token
. The expiration time of the refresh token itself is one week.
please notice in the response body of the refresh-token process, a new refresh token will be generated, so we suggest
replacing the newly generated refresh token with the old one, for future refresh requests.
Sample Code
response = requests.request(
"POST",
auth_url,
data={
"grant_type": "refresh_token",
"refresh_token": refresh_token,
"client_id": client_id,
"client_secret": client_secret,
}
)
access_token = response.json()["access_token"]
new_refresh_token = response.json()["refresh_token"]
curl -X POST -d "refresh_token=$REFRESH_TOKEN"\
-d "client_id=$CLIENT_ID" \
-d "client_secret=$CLIENT_SECRET" \
-d "grant_type=refresh_token" \
$AUTH_URL
Request Data Example
POST /oauth2/token/ HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Host: auth.qbitpay.org
grant_type=refresh_token&
refresh_token=upTFapSZfpJISYeo0YsZVjf8X29SBy&
client_id=MY_CLIENT_ID&
client_secret=MY_CLEINT_SECRET
Response Data Example
HTTP/1.1 200 OK
Content-Type: application/json
{
"access_token":"mAGJQqnhLBEZ5UMVAvHVNruOzAyZVs",
"expires_in":86400,
"token_type":"Bearer",
"scope":"settlement.single.submit settlement.single.verify",
"refresh_token":"BLVE2AleqqLHPBmGad4HAQEmqkPr4b"
}
Error Handling
In this section we will list some of the errors that you may encounter while trying to obtian or refresh your tokens.
400_INVALID_SCOPE
{"error": "invalid_scope"}
Reasons
- You're acquiring a token with a scope that is not defined. (e.g. wrong scope name)
- One or more of the scopes in your request is unavailable for your user.
400_INVALID_GRANT
{
"error"
:
"invalid_grant", "error_description"
:
"..."
}
Reasons
- You have specified the
username
orpassword
in your request incorrectly.
401_INVALID_CLIENT
{
"error"
:
"invalid_client"
}
Reasons
- The
client_id
specified in your request is not correct. - The
client_secret
specified in your request is not correct.
Enums
1. Bank IDs
Each bank has a unique numeric identifier. The mappings are as follows.
Name | Persian Name | ID |
---|---|---|
Shahr | شهر | 1 |
Melli | ملی | 2 |
Mellat | ملت | 3 |
Tejarat | تجارت | 4 |
Keshavarzi | کشاورزی | 5 |
Refah Kargaran | رفاه کارگران | 6 |
Pasargad | پاسارگاد | 7 |
Sepah | سپه | 8 |
Saderat | صادرات | 9 |
Resalat | رسالت | 10 |
Tose Saderat | توسعه صادرات | 11 |
Sina | سینا | 12 |
Ayande | آینده | 13 |
Maskan | مسکن | 14 |
Saman | سامان | 15 |
Karafarin | کارآفرین | 16 |
Eghtesad Novin | اقتصاد نوین | 17 |
Parsian | پارسیان | 18 |
Ansar | انصار | 19 |
Sarmaye | سرمایه | 20 |
Dey | دی | 21 |
gavamin | قوامین | 22 |
gardeshgari | گردشگری | 23 |
khavarmiane | خاورمیانه | 24 |
Sannat Madan | صنعت و معدن | 25 |
tose_taavon | توسعه تعاون | 26 |
Iran_Zamin | ایران زمین | 27 |
Post Bank | پست بانک | 28 |
Mehr_Iranian | مهر ایرانیان | 29 |
Hekmat Iranian | حکمت ایرانیان | 30 |
Moassese Etebari Tose | موسسه اعتباری توسعه | 31 |
Moassese Etebari Melal | موسسه اعتباری ملل | 32 |
Moassese Etebari Kosar | موسسه اعتباری کوثر | 33 |
Moassese Etebari Noor | موسسه اعتباری نور | 34 |
Mehr Eghtesad | مهر اقتصاد | 35 |
Iran_venezuela | مشترک ایران - ونزوئلا | 36 |
Caspian | موسسه اعتباری كاسپین | 37 |
Markazi | بانک مرکزی | 38 |
APIs
1. Base URLs
The base URLs for our staging and production API servers are as follows:
Environment | URL |
---|---|
Production | https://inquisitor.toman.ir/api/v1/ |
Staging | https://inquisitor-staging.qcluster.org/api/v1/ |
Note: Please pay attention to trailing slash at the end of the urls for all endpoints.
2. Card To IBAN
Used to retrieve the IBAN from a given card number.
Sample Code
import requests
url = "https://inquisitor.toman.ir/api/v1/card_to_iban/"
payload = json.dumps({
"card_number": "6789054325678412"
})
headers = {
'Content-Type': 'application/json'
}
response = requests.request("POST", url, headers=headers, data=payload)
curl --location 'https://inquisitor.toman.ir/api/v1/card_to_iban/' \
--header 'Content-Type: application/json' \
--data '{
"card_number": "6789054325678412"
}'
Scope
inquiry.card_to_iban.read
Request Body
{
"card_number": "6789054325678412"
}
Response Body
The response body contains the card number and IBAN.
Response Data Example
{
"card_number": "234123465431245",
"iban": "IR346786453214598456708342"
}
3. Account To IBAN
Used to retrieve the IBAN from a given account number.
Sample Code
import requests
url = "https://inquisitor.toman.ir/api/v1/account_number_to_iban/"
payload = json.dumps({
"account_number": "732456732147",
"bank_id": 2
})
headers = {
'Content-Type': 'application/json'
}
response = requests.request("POST", url, headers=headers, data=payload)
curl --location 'https://inquisitor.toman.ir/api/v1/account_number_to_iban/' \
--header 'Content-Type: application/json' \
--data '{
"account_number": "732456732147",
"bank_id": 2
}'
Scope
inquiry.account_number_to_iban.read
Request Body
{
"account_number": "732456732147",
"bank_id": 2
}
Response Body
The response body contains the account number, IBAN, bank ID, bank name, account owners, account status, and any errors.
Response Data Example
{
"iban": "IR4432795460000007634516001",
"deposit": "732456732147",
"deposit_description": "حساب فعال است",
"deposit_comment": "",
"bank_name": "بانک ملی ایران",
"bank_id": "2",
"deposit_owners": [
{
"firstName": "",
"lastName": "الکام توسعه آماد"
}
],
"error_description": "بدون خطا"
}
4. IBAN Inquiry
Used to retrieve the IBAN details.
Sample Code
import requests
url = "https://inquisitor.toman.ir/api/v1/iban_inquiry/"
payload = json.dumps({
"iban": "IR4432795460000007634516001"
})
headers = {
'Content-Type': 'application/json'
}
response = requests.request("POST", url, headers=headers, data=payload)
curl --location 'https://inquisitor.toman.ir/api/v1/iban_inquiry/' \
--header 'Content-Type: application/json' \
--data '{
"iban": "IR4432795460000007634516001"
}'
Scope
inquiry.iban_inquiry.read
Request Body
{
"iban": "IR4432795460000007634516001"
}
Response Body
The response body contains the account number, IBAN, bank ID, bank name, account owners, account status, and any errors.
Response Data Example
{
"iban": "IR4432795460000007634516001",
"deposit": "732456732147",
"deposit_description": "حساب فعال است",
"deposit_comment": "",
"bank_name": "بانک ملی ایران",
"bank_id": "2",
"deposit_owners": [
{
"firstName": "",
"lastName": "الکام توسعه آماد"
}
],
"error_description": "بدون خطا"
}
5. Wage Estimation
Used to retrieve the possibility of transferring via PAYA, SATNA, and A2A, along with the wage amount and transfer time, based on the given source and destination bank IDs and transfer amount.
Sample Code
import requests
url = "https://inquisitor.toman.ir/api/v1/wage-estimation/"
payload = json.dumps({
"amount" : 700000000,
"source_bank_id": 1,
"destination_bank_id": 2
})
headers = {
'Content-Type': 'application/json'
}
response = requests.request("POST", url, headers=headers, data=payload)
curl --location 'https://inquisitor.toman.ir/api/v1/wage-estimation/' \
--header 'Content-Type: application/json' \
--data '{
"amount" : 700000000,
"source_bank_id": 1,
"destination_bank_id": 2
}'
Scope
inquiry.wage_estimation.read
Request Body
{
"amount" : 700000000,
"source_bank_id": 1,
"destination_bank_id": 2
}
Response Body
The response body contains the possibility to transfer using PAYA, SATNA, and A2A, along with the wage amount and transfer time.
Response Data Example
{
"paya": {
"active": true,
"wage": 30000,
"estimated_time": "1403-07-02T18:45:00"
},
"satna": {
"active": true,
"wage": 140000,
"estimated_time": "1403-07-03T07:00:00"
},
"a2a": {
"active": false,
"wage": 0,
"estimated_time": null
}
}