Generare cheie de acces
Pentru a folosi acest API, este nevoie sa generati o cheie de acces din ecranul Utilizatori Integrare API Genereaza cheie de acces.
- Fiecare request trebuie sa trimita headerul de autorizare de tip Bearer ce va contine cheia de acces si headerul pentru identificarea firmei X-Saga-Cod-Fiscal.
- In anumite situatii, raspunsul va contine, pe langa statusul operatiei, si o noua cheie de acces in header-ul X-Saga-Refresh-Token. Aceasta trebuie salvata pentru a putea fi folosita la urmatorul apel. In caz contrar, cheia de acces va fi blocata si va trebui sa generati una noua.
- Ecranul "Integrare API" poate fi accesat doar de utilizatori de tip Admin.
- Endpoint-urile prezentate sunt unice pentru fiecare cod fiscal.
Import date
- 200: import realizat integral cu succes
- 207: import realizat partial cu succes
- 422: import esuat in totalitate
- 400: request eronat
Mai jos aveti cateva exemple de consumare a API-ului:
using Newtonsoft.Json;
using System.Net.Http.Headers;
var uri = new Uri("https://web.sagasoft.ro/api/v20260225/Import");
// Inlocuiti valoarea codului fiscal cu cea a firmei pentru care se doreste importul facturilor
string codFiscal = "1234";
// Inlocuiti valoarea token-ului de acces cu cea generata din contul de Saga Web
string token = "TOKEN_DE_ACCES";
// Inlocuiti valoarea filePath cu calea catre fisierul XML care se doreste a fi importat
string filePath = "C:\\calea\\catre\\fisierul\\de\\importat.xml";
//Setati valoarea importAutomat daca doriti utilizarea automatizarii la import
bool importAutomat = true;
HttpClient httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
httpClient.DefaultRequestHeaders.Add("X-Saga-Cod-Fiscal", codFiscal);
using var form = new MultipartFormDataContent();
using var fileStream = File.OpenRead(filePath);
var fileContent = new StreamContent(fileStream);
form.Add(fileContent, "file", Path.GetFileName(filePath));
form.Add(new StringContent(importAutomat.ToString().ToLowerInvariant()), "importAutomat");
var response = await httpClient.PostAsync(uri, form);
var result = await response.Content.ReadAsStringAsync();
string newToken = string.Empty;
//In response.Headers veti primi un token actualizat care va trebui salvat si folosit la urmatorul apel API
if (response.Headers.TryGetValues("X-Saga-Refresh-Token", out var values))
{
newToken = values.FirstOrDefault();
}
switch ((int)response.StatusCode)
{
//Status Code 207 - import realizat partial sau cu avertizari
case 207:
//Status code 422 - import realizat fara succes
case 422:
// Raspuns tip fisier text - raport de import cu probleme
var reportBytes = await response.Content.ReadAsByteArrayAsync();
string reportFileName = response.Content.Headers.ContentDisposition.FileName;
string savePath = Path.Combine(Path.GetDirectoryName(filePath) ?? ".", reportFileName);
await File.WriteAllBytesAsync(savePath, reportBytes);
Console.WriteLine("Importul a intampinat probleme. Raportul a fost salvat la: " + savePath);
break;
default:
TaskResponse tResponse = JsonConvert.DeserializeObject(result);
if (tResponse.Success == false)
{
//Nu s-a realizat importul
}
break;
}
//Pentru a deserializa raspunsul primit din API in urma importului, trebuie definita o clasa ca mai jos
class TaskResponse
{
//Defineste starea importului
public bool Success { get; set; }
//Defineste mesajul primit in urma importului
public string Message { get; set; }
}
<?php
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => 'https://web.sagasoft.ro/api/v20260225/Import',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => '',
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 0,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => 'POST',
// Inlocuiti valoarea de mai jos cu calea catre fisierul XML care se doreste a fi importat
// Setati valoarea parametrului importAutomat de mai jos daca doriti utilizarea automatizarii la import
CURLOPT_POSTFIELDS => array(
'file'=> new CURLFILE('C:\\CALEA\\CATRE\\FISIERUL\\DE\\IMPORTAT.xml'),
'importAutomat' => 'true'
),
CURLOPT_HTTPHEADER => array(
// Inlocuiti valoarea codului fiscal cu cea a firmei pentru care se doreste importul facturilor
'X-Saga-Cod-Fiscal: 1234',
// Inlocuiti valoarea token-ului de acces cu cea generata din contul de Saga Web
'Authorization: Bearer TOKEN_DE_ACCESS'
),
));
$response = curl_exec($curl);
if ($response === false) {
echo "cURL error: " . curl_error($curl);
echo "
cURL errno: " . curl_errno($curl);
curl_close($curl);
exit;
}
$newToken = '';
$statusCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
// In response headers veti primi un token actualizat care va trebui salvat si folosit la urmatorul apel API
$headerSize = curl_getinfo($curl, CURLINFO_HEADER_SIZE);
$headers = substr($response, 0, $headerSize);
if (preg_match('/Authorization:\s*(.*)/i', $headers, $matches)) {
$newToken = trim($matches[1]);
var_dump($newToken);
// Salvati token-ul primit
}
// Extrage body-ul raspunsului
$responseBody = substr($response, $headerSize);
if($statusCode == 207 || $statusCode == 422){
// Status code 207 - import realizat cu succes partial sau cu avertizari
// Status code 422 - import realizat fara succes
$fileName = 'RaportImport.txt';
if (preg_match('/Content-Disposition:.*filename\*?=(?:UTF-8\'\')?"?([^";\r\n]+)"?/i', $headers, $matches)) {
$fileName = trim($matches[1]);
}
$outputPath = 'C:\\CALEA\\CATRE\\SALVAREA\\RASPUNSULUI\\' . $fileName;
file_put_contents($outputPath, $responseBody);
if ($statusCode == 207) {
echo 'Import realizat partial. Raport salvat in: ' . $outputPath;
} else {
echo 'Import esuat. Raport salvat in: ' . $outputPath;
}
}
else{
$tResponse = json_decode($responseBody);
if ($tResponse->success === false) {
echo 'Import fara succes: ' . $tResponse->message;
} else {
echo 'Import cu succes: ' . $tResponse->message;
}
}
import http.client
import mimetypes
import json
import os
from urllib.parse import urlparse
from codecs import encode
url = "https://web.sagasoft.ro/api/v20260225/Import"
parsed_url = urlparse(url)
conn = http.client.HTTPConnection(parsed_url.netloc)
dataList = []
boundary = 'wL36Yn8afVp8Ag7AmP8qZ0SA4n1v9T'
// Inlocuiti valoarea de mai jos cu calea catre fisierul XML care se doreste a fi importat
file_path = r"/C:/CALEA/CATRE/FISIERUL/DE/IMPORTAT.XML"
file_name = os.path.basename(file_path)
# Setati valoarea parametrului de mai jos daca doriti utilizarea automatizarii importului
importAutomat = False;
dataList.append(encode('--' + boundary))
dataList.append(encode('Content-Disposition: form-data; name="importAutomat"'))
dataList.append(encode(''))
dataList.append(encode(str(importAutomat).lower()))
dataList.append(encode('--' + boundary))
dataList.append(encode(
f'Content-Disposition: form-data; name="file"; filename="{file_name}"'
))
fileType = mimetypes.guess_type(file_path)[0] or 'application/octet-stream'
dataList.append(encode(f'Content-Type: {fileType}'))
dataList.append(encode(''))
with open(file_path, 'rb') as f:
dataList.append(f.read())
dataList.append(encode('--'+boundary+'--'))
dataList.append(encode(''))
body = b'\r\n'.join(dataList)
payload = body
// Inlocuiti valoarea codului fiscal cu cea a firmei pentru care se doreste importul fisierului
// Inlocuiti valoarea cheii de acces cu cea generata din contul de Saga Web
headers = {
'X-Saga-Cod-Fiscal': '1234',
'Authorization': 'Bearer TOKEN_DE_ACCES',
'Content-type': 'multipart/form-data; boundary={}'.format(boundary)
}
conn.request("POST", parsed_url.path, payload, headers)
res = conn.getresponse()
newToken = ""
# In response.headers veti primi un token actualizat care va trebui salvat si folosit la urmatorul apel API
authorizationHeader = res.getheader("X-Saga-Refresh-Token")
if authorizationHeader:
# Salvati noua cheie de acces pentru urmatorul apel API
newToken = authorizationHeader
statusCode = res.status
if statusCode in (207, 422):
# Status Code 207 - import realizat cu succes partial sau cu avertizari
# Status Code 422 - import realizat fara succes
# Raspuns tip fisier text - raport cu problemele intampinate
reportBytes = res.read()
contentDisposition = res.getheader("Content-Disposition") or ""
match = re.search(r'filename="?([^";]+)"?', contentDisposition)
reportFileName = match.group(1) if match else "RaportImport.txt"
with open(reportFileName, "wb") as f:
f.write(reportBytes)
print("Importul a intampinat probleme. Raportul a fost salvat la:", reportFileName)
else:
# Raspuns JSON - import realizat cu succes
result = res.read().decode("utf-8")
tResponse = json.loads(result)
if tResponse["success"] is False:
# Nu s-a realizat importul
print("Import failed:", tResponse["message"])
else:
print("Import realizat cu succes:", tResponse["message"])
OkHttpClient client = new OkHttpClient().newBuilder().build();
//Setati valoarea parametrului de mai jos daca doriti utilizarea automatizarii la import
boolean importAutomat = false;
File file = new File("C:/CALEA/CATRE/FISIERUL/DE/IMPORTAT.xml");
MultipartBody requestBody = new MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart("file", file.getName(),
RequestBody.create(file, MediaType.parse("application/octet-stream")))
.addFormDataPart("importAutomat", String.valueOf(importAutomat).toLowerCase())
.build();
Request request = new Request.Builder()
.url("https://web.sagasoft.ro/api/v20260225/Import")
.method("POST", body)
// Inlocuiti valoarea codului fiscal cu cea a firmei pentru care se doreste importul facturilor
.addHeader("X-Saga-Cod-Fiscal", "1234")
// Inlocuiti valoarea token-ului de acces cu cea generata din contul de Saga Web
.addHeader("Authorization", "Bearer TOKEN_DE_ACCES")
.build();
Response response = client.newCall(request).execute();
String newToken = "";
// La primirea raspunsului veti primi o cheie de acces actualizata care va trebui salvata si folosita la urmatorul apel API
String authorizationHeader = response.header("X-Saga-Refresh-Token");
if (authorizationHeader != null && !authorizationHeader.isEmpty()) {
newToken = authorizationHeader;
}
int statusCode = response.code();
if (statusCode == 207 || statusCode == 422) {
// Status code 207 - import realizat partial sau cu avertizari
// Status code 422 - import realizat fara succes
byte[] fileBytes = response.body().bytes();
String contentDisposition = response.header("Content-Disposition");
String fileName = "RaportImport.txt";
if (contentDisposition != null) {
Matcher matcher = Pattern.compile("filename\\*?=(?:UTF-8'')?\"?([^\";]+)\"?")
.matcher(contentDisposition);
if (matcher.find()) {
fileName = matcher.group(1);
}
}
Path outputPath = Paths.get(System.getProperty("user.home"), "Desktop", fileName);
Files.write(outputPath, fileBytes);
if (statusCode == 207) {
System.out.println("Import realizat partial. Raport salvat in: " + outputPath);
} else {
System.out.println("Import esuat. Raport salvat in: " + outputPath);
}
}
else{
// Status code 200 - import realizat cu succes, fara avertizari
String result = response.body().string();
ObjectMapper mapper = new ObjectMapper();
JsonNode json = mapper.readTree(result);
boolean success = json.get("success").asBoolean();
String message = json.get("message").asText();
System.out.println("Success: " + success);
System.out.println("Message: " + message);
}
Formatul fisierelor XML trebuie sa urmeze exemplul de mai jos:
Numele fișierului trebuie să fie în formatul
F_<cod-fiscal>_<numar-factura>_<data-factura>.xml.Pentru a importa mai multe facturi concomitent, repetați secvența
<Factura>...</Factura> în interiorul nodului <Facturi>.Dacă tag-ul
<FurnizorCIF> reprezintă codul fiscal al societății, factura se va importa în ecranul „Ieșiri”. În caz contrar, importul se va efectua în ecranul „Intrări”.Puteți obține un model de XML cu date folosind tipărirea din SAGA Desktop din ecranul „Ieșiri” și alegând opțiunea „Formular PDF” din lista situată în partea superioară a ecranului de tipărire. În folderul
TEMP\Facturi se va copia, pe lângă PDF, și XML-ul aferent facturii.<Facturi>
<Factura>
<Antet>
<FurnizorNume>
<FurnizorCIF>
<FurnizorNrRegCom>
<FurnizorCapital>
<FurnizorTara>
<FurnizorLocalitate>
<FurnizorJudet>
<FurnizorAdresa>
<FurnizorTelefon>
<FurnizorMail>
<FurnizorBanca>
<FurnizorIBAN>
<FurnizorInformatiiSuplimentare>
<GUID_cod_client> (Opțional, codul din aplicația proprie pentru clientul din Saga. Asocierea cu codul intern Saga se va salva în baza de date, pentru identificare ulterioară)
<ClientNume>
<ClientInformatiiSuplimentare>
<ClientCIF>
<ClientNrRegCom>
<ClientJudet> (Se completează codul județului, doar pentru terții din România, de exemplu, AB-pentru județul Alba)
<ClientTara> (Codul țării, de exemplu, FR- pentru Franța)
<ClientLocalitate>
<ClientAdresa>
<ClientBanca>
<ClientIBAN>
<ClientTelefon>
<ClientMail>
<FacturaNumar>
<FacturaData>
<FacturaScadenta>
<FacturaTaxareInversa> (Da/Nu)
<FacturaTVAIncasare> (Da/Nu)
<FacturaTip> (Opţional. Tipul de document din Saga. Ex: " " factură, "A" aviz, "B" bon de casa,"T" taxare inversă, "C" bon de casă cu cod fiscal)
<FacturaInformatiiSuplimentare>
<FacturaMoneda> (Opţional pentru RON)
<FacturaGreutate>
<FacturaAgent> (Opţional, codul agentului asociat facturii)
<FacturaAccize> (Opţional, valoarea accizelor din factură)
<FacturaIndexSPV> (Opţional, ID-ul de încărcare al e-Facturilor în SPV)
<FacturaIndexDescarcareSPV> (Opţional, ID-ul recipisei e-Facturilor)
<Cod> (Opţional, codul de client sau furnizor din Saga)
</Antet>
<Detalii>
<Continut>
<Linie>
<LinieNrCrt>
<Gestiune> (Opțional. Doar pentru evidenta cantitativ-valorică. Codul de gestiune.)
<Activitate> (Opţional)
<Proiect> (Opţional)
<Descriere>
<CodArticolFurnizor> (Opţional, doar pentru evidenta cantitativ-valorică. Reprezintă codul de produs pentru facturile de intrare)
<CodArticolClient> (Opțional, doar pentru evidenta cantitativ-valorică. Reprezintă codul de produs pentru facturile de ieșire)
<GUID_cod_articol> (Opțional, pentru evidenta cantitativ-valorică. Codul de produs din aplicația proprie. Asocierea cu codul de produs din Saga se salvează in baza de date, pentru identificare ulterioară)
<CodBare> (Opţional)
<InformatiiSuplimentare> (Opţional)
<UM>
<Cantitate>
<Pret>
<Valoare>
<ProcTVA> (Opţional)
<TVA>
<Cont> (Opţional)
<TipDeducere> (Opțional. Doar pentru importul facturilor de intrare. Tipul de deducere pentru TVA si cheltuială. Folosiți indicele "N50" pentru deductibilitate limitată la 50% sau "I" pentru nedeductibilitate integrală).
<PretVanzare> (Opțional. Doar pentru importul facturilor de intrare. Reprezintă prețul de vânzare al produsului, pentru o gestiune evaluată la preț de vânzare)
</Linie>
.......
<Linie>
.......
</Linie>
</Continut>
</Detalii>
<FacturaID> sau <GUID_factura> (Opţional, ID unic, din aplicatia proprie, pentru identificarea încasării. Asocierea cu ID-ul unic din Saga se salvează în baza de date, pentru identificare ulterioară).
</Factura>
.......
<Factura>
.......
</Factura>
.......
</Facturi>
Numele fișierului trebuie să fie în formatul
C_<cod-fiscal>_<numar-comandă>_<data-comandă>.xml.Pentru a importa mai multe comenzi concomitent, repetați secvența
<Comanda>...</Comanda> în interiorul nodului <Comenzi>.Dacă tag-ul
<FurnizorCIF> reprezintă codul fiscal al societății, comanda va fi de tip „Ieșire”. Altfel, comanda va fi considerată de tip „Intrare”.Puteți obține un model de XML cu date folosind butonul „Generare XML” din ecranul „Comenzi”, după poziționarea pe comanda de ieșire. În folderul
TEMP\Comenzi se va genera XML-ul aferent comenzii.<Comenzi>
<Comanda>
<Antet>
<FurnizorNume>
<FurnizorCIF>
<FurnizorNrRegCom>
<FurnizorCapital>
<FurnizorTara>
<FurnizorLocalitate>
<FurnizorJudet>
<FurnizorAdresa>
<FurnizorTelefon>
<FurnizorMail>
<FurnizorBanca>
<FurnizorIBAN>
<FurnizorInformatiiSuplimentare>
<ClientNume>
<ClientInformatiiSuplimentare>
<ClientCIF>
<ClientNrRegCom>
<ClientJudet> (Se completează codul județului, doar pentru terții din România, de exemplu, AB- pentru județul Alba)
<ClientTara> (Codul țării, de exemplu, FR- pentru Franța)
<ClientLocalitate>
<ClientAdresa>
<ClientBanca>
<ClientIBAN>
<ClientTelefon>
<ClientMail>
<ComandaNumar>
<ComandaData>
<ComandaLivrare>
<ComandaInformatiiSuplimentare>
<ComandaMoneda> (Opţional pentru RON)
<ComandaGreutate>
<Cod> (Optional, codul de client sau furnizor din Saga)
</Antet>
<Detalii>
<Continut>
<Linie>
<LinieNrCrt>
<Gestiune> (Opțional. Doar pentru evidenta cantitativ-valorică. Codul de gestiune)
<Activitate> (Opţional)
<Descriere>
<CodArticolFurnizor> (Optional. Reprezintă codul de produs pentru comenzi de intrare)
<CodArticolClient> (Opțional. Reprezintă codul de produs pentru comenzi de ieșire)
<CodBare>
<InformatiiSuplimentare>
<UM>
<Cantitate>
<Pret>
<Valoare>
<ProcTVA> (Opţional)
<TVA>
<PretVanzare>(Opțional. Doar pentru importul comenzilor de intrare. Reprezintă prețul de vânzare al produsului, pentru o gestiune evaluată la preț de vânzare)
</Linie>
.......
<Linie>
.......
</Linie>
</Continut>
</Detalii>
</Comanda>
.......
<Comanda>
.......
</Comanda>
.......
</Comenzi>
Numele fișierului trebuie să fie în formatul
I_<data>.xml.Pentru a importa mai multe încasări concomitent, repetați secvența
<Linie>...</Linie>.Fișierul XML de încasări se poate importa și prin ecranele „Registru de casa” sau „Jurnal de banca”. Această variantă permite asocierea încasărilor cu facturile corespunzătoare.
<Incasari>
<Linie>
<Data>
<Numar>
<Suma>
<Cont> (Cont de trezorerie din clasa 5)
<ContClient> (Opţional)
<Explicatie>
<FacturaID> (Opţional - necesar pentru identificarea facturii încasate dacă aceasta a fost importată dintr-un XML)
<FacturaNumar> (Opţional - permite identificarea facturii dupa număr)
<CodFiscal> (Opţional)
<Moneda> (Opţional)
<Activitate> (Opţional)
<Proiect> (Opţional)
</Linie>
<Linie>
.......
</Linie>
.......
</Incasari>
Numele fișierului trebuie să fie în formatul
P_<data>.xml.Pentru a importa mai multe plăți concomitent, repetați secvența
<Linie>...</Linie>.Fișierul XML de plăți se poate importa și prin ecranele „Registru de casa” sau „Jurnal de banca”. Această variantă permite asocierea plăților cu facturile corespunzătoare.
<Plati>
<Linie>
<Data>
<Numar>
<Suma>
<Cont> (Cont de trezorerie din clasa 5)
<ContFurnizor> (Opţional)
<Explicatie>
<FacturaID> (Opţional - necesar pentru identificarea facturii încasate dacă aceasta a fost importată dintr-un XML)
<FacturaNumar> (Opţional)
<CodFiscal> (Opţional)
<Moneda> (Opţional)
<Activitate> (Opţional)
<Proiect> (Opţional)
</Linie>
<Linie>
.......
</Linie>
.......
</Plati>
Numele fișierului trebuie să fie în formatul
NC_<data>.xml.Pentru a importa mai multe articole contabile concomitent, repetați secvența
<Linie>...</Linie>.<NC>
<Linie>
<Data> D
<Numar> C (16)
<Suma> N(15,2)
<ContDebit> C (20)
<ContCredit> C (20)
<Explicatie> C (200)
<Moneda> (Optional - implicit "RON") C (3)
<Curs> (Optional) N(10,4)
<Suma_val> (Optional) N(15,2)
<Activitate> (Optional) C (16)
<Proiect> (Optional) C (16)
</Linie>
........
</NC>
Numele fișierului trebuie să fie în formatul
CLI_<data>.xml.Pentru a importa mai mulți clienți concomitent, repetați secvența
<Linie>...</Linie>.<Clienti>
<Linie>
<Cod> (opţional)
<Denumire>
<Cod_fiscal>
<Reg_com>
<Tara> (simbolul tarii ex.pt Romania - RO)
<Judet> (simbolul judetului)
<Localitate>
<Adresa> (opţional)
<Cont_banca> (opţional)
<Banca> (opţional)
<Tel> (opţional nr. de telefon)
<Email> (opţional)
<Discount> (opţional procent discount implicit)
<Informatii> (opţional informatii suplimentare)
<Guid_cod> (opţional cod extern)
</Linie>
<Linie>
.......
</Linie>
.......
</Clienti>
Numele fișierului trebuie să fie în formatul
ART_<data>.xml.Pentru a importa mai multe articole concomitent, repetați secvența
<Linie>...</Linie>.<Articole>
<Linie>
<Cod> (opţional)
<Denumire>
<Cod_NC>
<Cod_CPV>
<UM> (unitatea de măsură)
<Tip> (codul sau denumirea corespunzatoare din ecranul Tipuri de articole/ servicii)
<TVA> (procentul de TVA)
<Pret> (opţional pretul de vanzare fără TVA)
<Pret_TVA> (opţional pretul de vanzare cu TVA)
<Cod_bare> (opţional codul de bare)
<Informatii> (opţional informatii suplimentare)
<Guid_cod> (opţional cod extern)
<Greutate> (opţional, greutatea neta)
<Greutate_B> (opţional, greutatea bruta)
</Linie>
<Linie>
.......
</Linie>
.......
</Articole>