Uzņēmumu konteksts jūsu lietotnē.
Lasiet juridisko personu ierakstus ar FTM API. Sāciet ar vienu parakstītu pieprasījumu un savienojiet datus ar sava servera procesiem.
Galapunktu katalogs →Pirmais pieprasījums
- 01
Izveidojiet atslēgu
Pierakstieties un atveriet Konts → API atslēgas. Izvēlieties nosaukumu, legal-entities:read tvērumu un pēc vajadzības derīguma termiņu. Ja API atslēgas jūsu kontam nav pieejamas, sazinieties ar FTM atbalstu.
- 02
Saglabājiet noslēpumu
Nokopējiet noslēpumu, kad tas parādās, un glabājiet to droši savā serverī. Vēlāk to nevar izgūt. Katrai integrācijai izmantojiet atsevišķu atslēgu.
- 03
Izsauciet juridiskās personas galapunktu
Iestatiet četrus vides mainīgos un palaidiet piemēru. Izmantojiet īstu 11 ciparu reģistrācijas numuru un atbilstošās vides API adresi.
export FTM_API_BASE='https://api.ftm.lv'
export FTM_REGCODE='YOUR_11_DIGIT_REGISTRATION_NUMBER'
export FTM_API_KEY='ak_YOUR_PUBLIC_KEY'
# Supply FTM_API_SECRET through your server's secret manager.
# For an interactive shell (bash), avoid putting it in shell history:
read -rsp 'API Secret: ' FTM_API_SECRET; export FTM_API_SECRET; echo
python3 ftm_api.py
# or: node ftm-api.mjsIestatiet FTM_API_BASE uz https://api.ftm.lv. Izveidojiet API atslēgu šīs vides sadaļā Konts → API atslēgas. Galapunkti sākas ar /service/api/v1.
Serveru lietotnēm
HMAC noslēpumi jāglabā serverī. Neiekļaujiet tos pārlūka JavaScript, publiskās SPA lietotnēs vai mobilajās lietotnēs. JavaScript piemērs darbojas Node.js vidē.
Pieprasījuma parakstīšana
Katram pieprasījumam ir jauns laika zīmogs un nejaušs nonce. Parakstiet sešus laukus ar HMAC-SHA256, izmantojot izsniegtā API Secret teksta UTF-8 baitus. Rezultātu sūtiet kā 64 mazo burtu heksadecimālās rakstzīmes. Pašu noslēpumu nekad nesūtiet.
HTTP_METHOD
EXACT_ESCAPED_PATH
CANONICAL_QUERY
TIMESTAMP
NONCE
SHA256_RAW_BODYSavienojiet laukus ar tieši piecām LF jaunrindas rakstzīmēm. Beigās nav jaunrindas. Aprēķiniet jaucējvērtību precīziem satura baitiem, ieskaitot atstarpes; arī tukšam saturam ir SHA-256 jaucējvērtība.
Ceļš: parakstiet precīzu kodēto ceļu, ko sūtāt pieprasījumā. To nedekodējiet, netīriet un nepārkodējiet. Procentkodējuma reģistrs, beigu slīpsvītra un atkārtotas slīpsvītras ir nozīmīgas. /foo%2Fbar, /foo%2fbar, /foo_bar, /foo/bar/ un /foo//bar ir atšķirīgi ceļi.
Vaicājums: dekodējiet procentkodējumu un + kā atstarpi, kārtojiet lauku nosaukumus pēc UTF-8 baitiem un saglabājiet atkārtotu vērtību secību. Izmantojiet formas kodējumu: atstarpe kļūst par +, pluszīme par %2B, procentkodējums ir ar lielajiem burtiem. A–Z a–z 0–9 - . _ ~ paliek nemainīti. Lauks bez vērtības kļūst par key=. Noraidiet kļūdainu kodējumu un nekodētus semikolus. Tukšs vaicājums ir tukšs lauks.
| Ievade | Kanoniskais vaicājums |
|---|---|
| b=2&a=1 | a=1&b=2 |
| a=2&a=1&a=2 | a=2&a=1&a=2 |
| q=a%20b | q=a+b |
| q=a+b | q=a+b |
| q=%2B | q=%2B |
| flag&empty= | empty=&flag= |
| "" | "" |
HMAC testa vektori
Bezsaistes piemēri ar izdomātu atslēgu un noslēpumu. Izmantojiet precīzus UTF-8 baitus bez BOM un beigu rindas pārtraukuma. Kanoniskajā virknē ir pieci LF atdalītāji, bez LF beigās; JSON pieraksts rāda precīzo saturu. API atslēga izvēlas piekļuves datus, bet nav kanoniskās virknes lauks. POST piemērs pārbauda tikai kodējumu, nevis atbalstītu darbību. Fiksētais laiks un nonce paredzēti testiem, nevis īstiem pieprasījumiem.
Lejupielādēt testa vektorus (JSON){
"name": "empty-get",
"key": "ak_documentation_test_only",
"secret": "ftm_fake_secret_DO_NOT_USE",
"method": "GET",
"path": "/service/api/v1/legal-entities/40000000000",
"query": "",
"body": "",
"timestamp": 1789336800,
"nonce": "AAECAwQFBgcICQoLDA0ODw",
"canonical_query": "",
"body_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"canonical": "GET\n/service/api/v1/legal-entities/40000000000\n\n1789336800\nAAECAwQFBgcICQoLDA0ODw\ne3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"signature": "1a0314746224b5356b87590de0a404b5382ef36074020f4890ebfc878483b66f"
}{
"name": "utf8-body-and-query",
"key": "ak_documentation_test_only",
"secret": "ftm_fake_secret_DO_NOT_USE",
"method": "POST",
"path": "/service/api/v1/%C4%81//x%2Fy/",
"query": "z=last&a=2&a=1&space=a%20b&plus=%2B&utf=%C4%81",
"body": "{\"message\":\"Sveiki, Rīga\"}",
"timestamp": 1789336800,
"nonce": "AAECAwQFBgcICQoLDA0ODw",
"canonical_query": "a=2&a=1&plus=%2B&space=a+b&utf=%C4%81&z=last",
"body_sha256": "5d0358713e4db6811b419f86478083965ad4bfdcd1919dfe1f5c2f19c58907d6",
"canonical": "POST\n/service/api/v1/%C4%81//x%2Fy/\na=2&a=1&plus=%2B&space=a+b&utf=%C4%81&z=last\n1789336800\nAAECAwQFBgcICQoLDA0ODw\n5d0358713e4db6811b419f86478083965ad4bfdcd1919dfe1f5c2f19c58907d6",
"signature": "6d57bebafb27ec31447339a28615802400e3a8f3b3c1151c200c8a0fc3e5b01c"
}Obligātās pieprasījuma galvenes
- X-API-Key
- Publiskā atslēga, kas sākas ar ak_.
- X-API-Timestamp
- Unix laika zīmogs veselās sekundēs. Sinhronizējiet servera pulksteni.
- X-API-Nonce
- Jauns nonce katram pieprasījumam: vismaz 16 droši nejauši baiti, base64url bez papildinājuma. Atļautais garums: 22–128 rakstzīmes.
- X-API-Signature
- 64 mazo burtu heksadecimālās rakstzīmes: HMAC-SHA256(secret, kanoniskais pieprasījums).
Python un JavaScript piemēri
Pilni klienti bez papildu bibliotēkām. Tie saglabā precīzu ceļu un saturu, pārbauda HTTPS sertifikātus un neseko pāradresācijām. Katru atkārtojumu parakstiet ar jaunu nonce.
"""Python 3.10+, standard library only. Keep API secrets on your server."""
import base64
import hashlib
import hmac
import http.client
import os
import re
import secrets
import sys
import time
from urllib.parse import parse_qsl, quote_plus, urlencode, urlsplit
def canonical_query(raw):
if ';' in raw or re.search(r'%(?![0-9A-Fa-f]{2})', raw):
raise ValueError('Invalid query encoding')
pairs = parse_qsl(raw, keep_blank_values=True, encoding='utf-8', errors='strict')
# Stable sort by UTF-8 key; preserve duplicate-value ordering.
pairs.sort(key=lambda pair: pair[0].encode('utf-8'))
return urlencode(pairs, quote_via=quote_plus, safe='~')
def canonical_request(method, path, query, timestamp, nonce, body=b''):
if not re.fullmatch(r"[!#$%&'*+.^_`|~0-9A-Za-z-]+", method):
raise ValueError('Invalid HTTP method')
if not re.fullmatch(r"/(?:[A-Za-z0-9\-._~!$&'()*+,;=:@/]|%[0-9A-Fa-f]{2})*", path):
raise ValueError('Use the exact escaped path')
if not re.fullmatch(r'[A-Za-z0-9_-]{22,128}', nonce):
raise ValueError('Invalid nonce')
if type(timestamp) is not int or timestamp < 0:
raise ValueError('Invalid timestamp')
return '\n'.join([method.upper(), path, canonical_query(query), str(timestamp), nonce,
hashlib.sha256(body).hexdigest()])
def sign(secret, method, path, query, timestamp, nonce, body=b''):
canonical = canonical_request(method, path, query, timestamp, nonce, body)
# Do not base64-decode the issued secret. Use its literal UTF-8 bytes.
return hmac.new(secret.encode('utf-8'), canonical.encode('utf-8'), hashlib.sha256).hexdigest()
def main():
base = urlsplit(os.environ['FTM_API_BASE'])
key, secret, regcode = (os.environ[k] for k in ('FTM_API_KEY', 'FTM_API_SECRET', 'FTM_REGCODE'))
if not re.fullmatch(r'[0-9]{11}', regcode):
raise ValueError('FTM_REGCODE must contain 11 digits')
if not base.hostname or base.username or base.password or base.path not in ('', '/') or base.query or base.fragment:
raise ValueError('FTM_API_BASE must be an origin without credentials, path, query or fragment')
if base.scheme != 'https':
raise ValueError('HTTPS required')
method, path, query, body = 'GET', '/service/api/v1/legal-entities/' + regcode, '', b''
timestamp = int(time.time())
nonce = base64.urlsafe_b64encode(secrets.token_bytes(16)).rstrip(b'=').decode('ascii')
headers = {'X-API-Key': key, 'X-API-Timestamp': str(timestamp), 'X-API-Nonce': nonce,
'X-API-Signature': sign(secret, method, path, query, timestamp, nonce, body),
'Accept': 'application/json'}
connection = http.client.HTTPSConnection(base.hostname, base.port, timeout=30)
try:
# http.client sends this exact escaped target and does not follow redirects.
connection.request(method, path + ('?' + query if query else ''), body=body, headers=headers)
response = connection.getresponse()
while chunk := response.read(65536):
sys.stdout.buffer.write(chunk)
sys.stdout.buffer.write(b'\n')
return 0 if response.status == 200 else 1
finally:
connection.close()
if __name__ == '__main__':
try:
sys.exit(main())
except (KeyError, ValueError, OSError, http.client.HTTPException):
sys.exit('Request failed. Check configuration, connectivity and API access.')
Piekļuve un darbība
Atslēgas tvērumi
Tvērumi nosaka, kurus galapunktus atslēga var izsaukt un kādus datus saņemt. Pieprasiet tikai integrācijai vajadzīgos tvērumus. Ierobežotas pieejamības personas dati ir pieejami tikai tad, ja atbilstoša piekļuve ir gan atslēgai, gan tās kontam.
Ierobežojumi un kļūdas
Noklusējuma paraksta laika logs ir ±300 sekundes; operators to var saīsināt. Nonce nedrīkst atkārtoti izmantot ar to pašu atslēgu pieņemtajā logā, ieskaitot pulksteņa nobīdi nākotnē. Pašlaik atļauti 100 autentificēti pieprasījumi minūtē uz atslēgu vienā servera instancē, papildus esošajam IP ierobežojumam. Ievērojiet 429 un Retry-After, ja tas norādīts; pirms atkārtošanas nogaidiet un izveidojiet jaunu parakstu.
- identity:read
- Pārbaudīt, kura API atslēga ir autentificēta.
- legal-entities:read
- Lasīt pilnu juridiskās personas ierakstu un pieejamās saistības. Personas identifikatori netiek iekļauti.
- legal-entities:personal-details
- Iekļaut ierobežotas pieejamības personas datus. Nepieciešams legal-entities:read un konts ar apstiprinātu piekļuvi šiem datiem.
401: trūkstoša, nederīga, novecojusi, atsaukta vai atkārtota autentifikācija, nedrošs transports vai neatbalstīts satura kodējums. 403: trūkst tvēruma vai atļaujas. 400: nederīga ievade. 404: ieraksts vai ceļš nav atrasts. 413: saturs par lielu. 429: pieprasījumu limits. 500: servera kļūda. Kļūdu objekti izmanto code un message_key; nepaļaujieties uz tekstu angļu valodā.
{
"code": "invalid_api_authentication",
"message_key": "error.unknown"
}Stabilie servisa API kļūdu kodi
Šie kodi attiecas uz parakstītajiem servisa galapunktiem. Atslēgu pārvaldība izmanto atsevišķus sesijas galapunktus. Nezināmi ceļi, neatbalstītas metodes, pārāk liels saturs vai starpniekservera kļūdas var atgriezt atbildi bez JSON: pārbaudiet HTTP statusu un Content-Type un apstrādājiet nezināmus kodus.
- 400 · invalid_registration_code
error.registry.invalid_registration_codeNorādiet regcode ar tieši 11 ASCII cipariem.
- 401 · invalid_api_authentication
error.unknownPārbaudiet HTTPS, četras galvenes, laiku, nonce, parakstu, atslēgu un konta piekļuvi. Autentifikācijas kļūdām apzināti ir viens kods; neatkārtojiet nemainītu pieprasījumu.
- 403 · forbidden
forbidden.messageAtslēgai trūkst tvēruma vai kontam vajadzīgo tiesību. Pirms atkārtošanas labojiet piekļuvi.
- 404 · not_found
error.registry.record_not_foundŠim reģistrācijas numuram nav juridiskās personas. Pārbaudiet numuru.
- 413 · body_too_large
error.invalid_inputSamaziniet pieprasījuma saturu; limits ir 4 MiB. Serveris vai starpniekserveris var agrāk atgriezt 413 bez JSON.
- 429 · rate_limited
error.rate_limitedIevērojiet Retry-After, ja norādīts; citādi palieliniet gaidīšanas intervālu. Katram mēģinājumam izmantojiet jaunu nonce un laiku.
- 500 · db_error
error.database.query_failedServera vai datubāzes kļūda. Atkārtojiet ar ierobežotu gaidīšanas intervālu un jaunu parakstu; ziņojiet par ilgstošām kļūdām.
Līdz 100 aktīvām atslēgām ar nebeigušos termiņu uz īpašnieku. Atsaukšana stājas spēkā nākamajā autentifikācijā visās instancēs. Rotācijai izveidojiet aizstājēju, atjauniniet serveri un atsauciet veco atslēgu. Pēdējās lietošanas laiks var tikt atjaunināts aptuveni reizi minūtē. Noslēpumi datubāzē ir šifrēti ar AES-256-GCM.
API pieprasījumiem vajadzīgs HTTPS. Izmantojiet atbilstošās vides API adresi un glabājiet API noslēpumu savā serverī.