Turkish lira (bank transfer)Retail5,750 Toman▲ +0.52%US dollarRetail279,750 Toman▼ -0.56%EuroRetail315,760 Toman▼ -0.26%USDT to TRYRetail53.03 TRY▼ -0.08%Turkish lira (bank transfer)Wholesale5,640 Toman• —US dollarWholesale275,720 Toman• —EuroWholesale311,210 Toman• —USDT to TRYWholesale52.05 TRY• —
Last update: 6 Oct 2026, 13:00 (Tehran time)

This page is currently available in Persian only.

Developer documentation

Hamta Partner Rates API

With this API your website, online store or bot receives your own partner account's rates directly from Hamta: no manual price entry, always in sync with the partner portal.

Overview

The Hamta API is a read-only REST service that returns JSON encoded as UTF-8. Each API key belongs to one partner account and returns that account's rates only: your cost from Hamta, and your customer price with the margin you set yourself in the partner portal. Reference market rates are not provided by this API.

Base URL

https://hamtagift.com

All requests must be sent over HTTPS.

Authentication

Every request must send the API key in the Authorization header as a Bearer token. Keys start with the prefix hamta_live_.

  1. Sign in to the partner portal and open the “API & Telegram” page.
  2. Create a new key (the Owner, Manager and Developer roles can create keys).
  3. The key is shown only once: store it in a secure environment variable on your server. Hamta keeps only a hashed copy; if you lose the key, revoke it and create a new one.
Request header
Authorization: Bearer hamta_live_…

Never put the API key in browser-side code (page JavaScript), a mobile app or a public code repository. Send requests from your server only.

Get rates

GET/api/partner/v1/rates

Returns the current rates of every instrument on your partner account. The request takes no parameters or body, and the response is never cached (Cache-Control: no-store).

Hours and access

The rates API answers on market days from 11:00 to 20:00 Tehran time (the last accepted request is at 19:59). It is closed on Fridays and official market holidays. Outside these hours it returns 503 with the code OUTSIDE_MARKET_HOURS; the Retry-After header gives the seconds until the next opening, and the next_open field gives its time (ISO 8601, UTC).

503
{
  "ok": false,
  "success": false,
  "error": "OUTSIDE_MARKET_HOURS",
  "message": "<string>",
  "market_hours": "11:00 - 20:00 Asia/Tehran",
  "next_open": "<ISO 8601 string>"
}

The IP allowlist is optional and is set up by Hamta support at your request. As long as no address is registered, your keys are accepted from any IP. Once one or more addresses are registered, every request from any other address is refused with 403 and the code IP_NOT_ALLOWED. Only exact public IPv4 or IPv6 addresses are accepted (no ranges), at most 10; the list applies to every key of your account and is shown in the partner portal (API & Telegram section).

403
{
  "ok": false,
  "success": false,
  "error": "IP_NOT_ALLOWED",
  "message": "<string>"
}

Response

A successful response has status 200. The structure below contains exactly the keys the API returns, with the data type written in place of each numeric value. To see the real response for your own account, open the “API & Telegram” page in the partner portal.

Successful response structure
{
  "ok": true,
  "partner": "<string>",
  "updatedAt": "<ISO 8601 string | null>",
  "note": "buy = customer buys (خرید از ما), sell = customer sells (فروش به ما). null = not configured.",
  "rates": [
    {
      "code": "havaleLir",
      "label": "لیر حواله ترکیه",
      "unit": "TOMAN",
      "unitBasis": 1,
      "partnerCost": {
        "retail": {
          "buy": "<decimal string | null>",
          "sell": "<decimal string | null>"
        },
        "wholesale": {
          "buy": "<decimal string | null>",
          "sell": "<decimal string | null>"
        }
      },
      "customerPrice": {
        "retail": {
          "buy": "<decimal string | null>",
          "sell": "<decimal string | null>"
        },
        "wholesale": {
          "buy": "<decimal string | null>",
          "sell": "<decimal string | null>"
        }
      }
    },
    …
  ]
}

Fields

FieldTypeDescription
okbooleanAlways true in a successful response and false in an error response.
partnerstringYour company name as registered on the partner account.
updatedAtstring | nullWhen Hamta's reference rates were last updated, in ISO 8601 (UTC); null if unknown.
notestringA fixed note on the meaning of buy, sell and null.
ratesarrayThe list of instruments, always in this order.
rates[].codestringStable instrument identifier; rely on this field in your code, not on label.
rates[].labelstringPersian display name of the instrument; it may change.
rates[].unit"TOMAN" | "TRY"Price unit: TOMAN is Iranian toman, TRY is Turkish lira.
rates[].unitBasisintegerThe price is for this many units; for example 1000 means the price of 1,000 units.
rates[].partnerCost{ retail, wholesale }Your cost from Hamta, split into retail and wholesale tiers.
rates[].customerPrice{ retail, wholesale }Your customer price: your cost plus the margin you set in the partner portal (1% by default). During a discount campaign that margin can go down to -2%, so the customer price can be better than your cost. null if no margin is set for that direction.
….buystring | nullThe price at which your customer buys from you.
….sellstring | nullThe price at which your customer sells to you.

Every price is a decimal string (up to 6 decimal places) or null. null means “not configured”; never treat it as zero.

Instruments

The rates list always contains these instruments, in this order:

codeInstrumentunitunitBasis
havaleLirTurkish lira transfer (toman per lira)TOMAN1
dollarUS dollar (toman per dollar)TOMAN1
euroEuro (toman per euro)TOMAN1
usdtToLirTurkish lira per USDTTRY1
AMD_1000Armenian dram (toman per 1,000 dram)TOMAN1000
usdtPriceToman per USDTTOMAN1
AFNAfghan afghani (toman per afghani)TOMAN1
onlineShopOnline-shop lira (toman per lira)TOMAN1
sipayHamtaCard lira (toman per lira)TOMAN1

Errors

API errors are returned as JSON with "ok": false and a code in "error". IP_NOT_ALLOWED and OUTSIDE_MARKET_HOURS also carry "success": false and a "message" in the language of your Accept-Language header (fa, en, tr, hy; English otherwise). The last two rows come from the site's security layer and are plain text, not JSON.

StatuserrorMeaningWhat to do
401missing_or_malformed_tokenThe Authorization header is missing or the key does not have the hamta_live_ format.Send the header as Bearer with the complete key.
401invalid_tokenThe key is unknown or revoked, or the partner account is not active.Create a new key in the partner portal or contact Hamta.
403IP_NOT_ALLOWEDThe key is valid, but the request did not come from an address on your account's IP allowlist.Send from a registered address, or contact Hamta support to change the list.
429rate_limitedMore than 60 requests in one minute with this key.Wait for the Retry-After header (seconds) and cache the result.
503OUTSIDE_MARKET_HOURSOutside market hours (11:00–20:00 Tehran time) or on a market holiday.Wait for Retry-After or next_open and keep showing your last valid rates.
503rates_unavailableRates are temporarily unavailable.Keep your last valid rates and try again later.
403—The request was refused by the site's security rules (plain-text Forbidden).If your request is ordinary, contact Hamta support.
429—Too many requests from one IP address (plain text).Wait for Retry-After and space your requests further apart.

Limits

  • At most 60 requests per minute per API key.
  • Requests are answered only on market days, 11:00–20:00 Tehran time (see Hours and access).
  • Requests refused because of the IP allowlist do not count against your key's per-minute limit.
  • In addition, each IP address has a separate site-wide request limit (sustained at most about 2 requests per second).
  • Only the GET method is supported.

Ready-to-use code samples

The samples below read the key from the HAMTA_API_KEY environment variable, check for errors and print each instrument's retail customer price. The PHP sample suits online stores such as WooCommerce or Laravel.

<?php
// Server side only: never send the API key to the browser.
$apiKey = getenv('HAMTA_API_KEY'); // hamta_live_...

$ch = curl_init('https://hamtagift.com/api/partner/v1/rates');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER     => ['Authorization: Bearer ' . $apiKey, 'Accept: application/json'],
    CURLOPT_TIMEOUT        => 10,
]);
$body   = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
$error  = curl_error($ch);
curl_close($ch);

if ($body === false) {
    throw new RuntimeException('Hamta API unreachable: ' . $error);
}
$data = json_decode($body, true); // null for the plain-text 403/429 of the security layer
if ($status !== 200 || !is_array($data) || empty($data['ok'])) {
    // 401: check the key. 429: wait for Retry-After. 503: keep your last good prices.
    throw new RuntimeException('Hamta API error: ' . ($data['error'] ?? ('HTTP ' . $status)));
}

foreach ($data['rates'] as $rate) {
    // Prices are decimal strings or null (= not configured). Keep them as strings
    // (e.g. bcmath) rather than float for money.
    $sellToCustomer = $rate['customerPrice']['retail']['buy'];
    echo $rate['code'], ': ', $sellToCustomer ?? 'not configured', PHP_EOL;
}

Best practices

  • Cache the result on your server for at least one minute rather than sending a request for every page view.
  • Handle prices as strings or an exact decimal type (Decimal, bcmath), not as floating-point numbers.
  • Look instruments up by code; label is for display only.
  • Show null as “not configured” and never substitute another number for it.
  • If a request fails, keep your last valid rates together with their updatedAt time.
  • Create a separate key for each service or environment, so you can revoke just that one if needed.

Ready to connect?

You create API keys in the partner portal. If you are not yet a Hamta partner, contact us to open a partner account.