Podrška

DTO Flow centar za pomoć

Praktične upute za pokretanje partnerskih razmjena, uspješan rad partnera, povezivanje sustava i dobivanje podrške kada je trebate.

Integracija

Automatizacija

Povežite pouzdane sustave kada se redovite datoteke trebaju automatski predavati, provjeravati ili preuzimati bez dodatnih ručnih koraka za vaš tim.

Istražite API predaju datoteka za partnerske feedovePregledajte sigurnost povezanih razmjena
Pristup

Privatni pristupni tokeni

Privatni pristupni tokeni su vjerodajnice ograničenog opsega za skripte, automatizirane zadatke i povezane partnerske sustave. Izradite token samo za feed i radnju koju automatizacija treba, odmah pohranite tajnu i opozovite stare tokene kada se promijeni vlasnik, poslužitelj ili integracija.

  • Koristite jedan token po skripti, planiranom poslu, partnerskom sustavu ili okruženju izvođenja.
  • Dodijelite samo potrebne opsege, primjerice provjeru razdoblja, predaju ili preuzimanje.
  • Pohranite tajnu u upravitelj lozinki, CI/CD tajnu, sigurno spremište ili spremište tajni planera.
  • Rotirajte tokene prema planiranom rasporedu i odmah nakon promjene vlasništva pristupa.
  • Pregledajte zapise feeda kada istražujete koji je token provjerio, prenio ili preuzeo datoteke.

Privatne pristupne tokene tretirajte kao lozinke. DTO Flow prikazuje punu vrijednost tajne samo jednom kako bi je sustav koji će je koristiti mogao sigurno pohraniti.

Datoteke

API-ji za prijenos i preuzimanje

Predaje putem API-ja i portala prate ista očekivanja feeda, validaciju, status razdoblja i povijest prihvaćenih datoteka. Vaš tim zadržava jedan dosljedan pregled bez obzira na to kako datoteka stiže.

  1. Pročitajte manifest feeda kako biste potvrdili očekivane datoteke, ekstenzije, ograničenja prijenosa i opsege.
  2. Izradite sesiju prijenosa za razdoblje određeno rokom i navedite svaku datoteku u paketu.
  3. Prenesite svaku datoteku na njezin izravni URL za prijenos prije isteka URL-a.
  4. Dovršite predaju kako bi DTO Flow mogao uskladiti datoteke, validirati ih i ažurirati razdoblje.
  5. Provjerite razdoblje prema roku prije pokretanja uvoza u odredišni sustav ili posla preuzimanja.
  6. Zatražite poveznice prihvaćenih datoteka i preuzmite svaku datoteku prije isteka URL-ova za preuzimanje.

Osnovni API URL: https://api.dtoflow.com. Za zahtjeve prema API-ju za automatizaciju šaljite Authorization: Bearer <private-access-token>. OpenAPI ugovor dostupan je na https://api.dtoflow.com/api/automation/v1/openapi.json.

Ako se automatizacija povezuje preko prilagođene API adrese, koristite isti osnovni URL za OpenAPI dokument.

Primjeri

Osnovni primjer razmjene datoteka

Počnite jednom malom, ponovljivom razmjenom: predajte očekivanu datoteku, dovršite predaju i preuzmite prihvaćenu datoteku kada je razdoblje spremno.

  • Prenesite CSV, Excel, ZIP ili druge očekivane datoteke iz planirane mape.
  • Provjerite ima li trenutačno razdoblje prihvaćenu datoteku prije pokretanja uvoza u odredišni sustav.
  • Preuzmite trenutačnu prihvaćenu predanu datoteku kada bude spremna.

.NET referenca: .NET kartica predstavlja DtoFlow.Integration tipove. Prikazane klase, uključujući DtoFlowAutomationClient i CreateAutomationUploadFileRequest, prikazuju oblik klijenta. Trenutačne integracije izradite prema primjeru s izravnim HTTP pozivima i objavljenom OpenAPI ugovoru.

Primjer koda

Predajte datoteku, dovršite predaju i preuzmite prihvaćene datoteke

Koristite varijable okruženja za tajne i postavke feeda specifične za okruženje izvođenja.

Program.cs
using System.Globalization;
using DtoFlow.Integration;
using DtoFlow.Integration.Models;

var baseUrl = Environment.GetEnvironmentVariable("DTOFLOW_BASE_URL") ?? "https://api.dtoflow.com";
var token = Environment.GetEnvironmentVariable("DTOFLOW_TOKEN")
    ?? throw new InvalidOperationException("Set DTOFLOW_TOKEN.");
var feedSlug = Environment.GetEnvironmentVariable("DTOFLOW_FEED_SLUG") ?? "supplier-prices";
var filePath = args.Length > 0 ? args[0] : "prices.csv";
var deadlineAt = DateTimeOffset.Parse(
    Environment.GetEnvironmentVariable("DTOFLOW_DEADLINE_AT") ?? "2026-06-01T12:00:00Z",
    CultureInfo.InvariantCulture);

using var httpClient = new HttpClient { BaseAddress = new Uri(baseUrl) };
var client = new DtoFlowAutomationClient(httpClient, token);
var fileInfo = new FileInfo(filePath);

try
{
    var session = await client.CreateUploadSessionAsync(
        feedSlug,
        deadlineAt,
        new[]
        {
            new CreateAutomationUploadFileRequest(
                FeedFileSlug: null,
                OriginalFileName: fileInfo.Name,
                ContentType: "text/csv",
                SizeBytes: fileInfo.Length)
        });

    using var upload = File.OpenRead(filePath);
    await client.UploadFileAsync(session.Files[0], upload);
    await client.CompleteUploadAsync(feedSlug, session.SubmissionId);

    AutomationPeriodStatus? period = null;
    for (var attempt = 0; attempt < 30; attempt++)
    {
        period = await client.GetPeriodStatusByDeadlineAsync(feedSlug, deadlineAt);
        if (period.AcceptedFilesAvailable)
        {
            break;
        }

        if (period.Status is "ValidationFailed" or "Rejected" or "Archived")
        {
            throw new InvalidOperationException(
                $"Submission {period.SubmissionId} finished with status {period.Status}.");
        }

        await Task.Delay(TimeSpan.FromSeconds(2));
    }

    if (period?.AcceptedFilesAvailable != true)
    {
        throw new TimeoutException("The accepted file was not ready within one minute.");
    }

    var accepted = await client.GetAcceptedFilesByDeadlineAsync(feedSlug, deadlineAt);
    foreach (var acceptedFile in accepted.Files)
    {
        using var destination = File.Create(acceptedFile.FileName);
        await client.DownloadAcceptedFileAsync(acceptedFile, destination);
        Console.WriteLine($"Downloaded {acceptedFile.FileName}");
    }
}
catch (DtoFlowAutomationException ex) when (ex.IsTenantAccessReadOnly)
{
    Console.Error.WriteLine($"Tenant access is {ex.TenantAccessState}; required action: {ex.TenantAccessRequiredAction}.");
    Environment.ExitCode = 2;
}
Referenca

API metode i .NET referenca

.NET referenca prikazuje uobičajene operacije klijenta. Postojeće integracije možete povezati s odgovarajućim krajnjim točkama izravnim HTTP pozivima ili prema objavljenom OpenAPI ugovoru.

GetManifestAsync(fileFeedSlug)
Čita smjer feeda, status, ograničenja prijenosa, očekivane datoteke, pravila podudaranja i ovlasti tokena kako bi svako pokretanje moglo potvrditi aktualne postavke.
GetPeriodStatusByDeadlineAsync(fileFeedSlug, deadlineAt)
Provjerava ima li očekivano razdoblje predaju, je li validacija završila i jesu li prihvaćene datoteke dostupne za preuzimanje.
CreateUploadSessionAsync(...) i CompleteUploadAsync(...)
Izrađuje izravna odredišta za prijenos, zatim označava predaju spremnom za podudaranje i validaciju nakon prijenosa svih datoteka.
GetAcceptedFilesByDeadlineAsync(...) i DownloadAcceptedFileAsync(...)
Dohvaća kratkotrajne izravne URL-ove za preuzimanje trenutačne prihvaćene predaje i sprema svaku prihvaćenu datoteku u lokalno odredište.
Primjer koda

Pročitajte manifest i provjerite spremnost razdoblja

Koristite ovo prije pokretanja uvoza u odredišni sustav ili posla preuzimanja.

check-period.cs
using System.Globalization;
using System.Linq;
using DtoFlow.Integration;

var baseUrl = Environment.GetEnvironmentVariable("DTOFLOW_BASE_URL") ?? "https://api.dtoflow.com";
var token = Environment.GetEnvironmentVariable("DTOFLOW_TOKEN")
    ?? throw new InvalidOperationException("Set DTOFLOW_TOKEN.");
var feedSlug = Environment.GetEnvironmentVariable("DTOFLOW_FEED_SLUG") ?? "supplier-prices";
var deadlineAt = DateTimeOffset.Parse(
    Environment.GetEnvironmentVariable("DTOFLOW_DEADLINE_AT") ?? "2026-06-01T12:00:00Z",
    CultureInfo.InvariantCulture);

using var httpClient = new HttpClient { BaseAddress = new Uri(baseUrl) };
var client = new DtoFlowAutomationClient(httpClient, token);

var manifest = await client.GetManifestAsync(feedSlug);
Console.WriteLine($"Feed: {manifest.Name} ({manifest.Slug})");
Console.WriteLine($"Direction: {manifest.Direction}; status: {manifest.Status}");
Console.WriteLine($"Token scopes: {string.Join(", ", manifest.TokenScopes)}");

foreach (var file in manifest.Files.OrderBy(file => file.SortOrder))
{
    Console.WriteLine(
        $"- {file.Slug}: {file.ExpectedExtension}, required={file.RequiredInSubmission}, validation={file.IsValidationEnabled}");
}

var period = await client.GetPeriodStatusByDeadlineAsync(feedSlug, deadlineAt);
if (!period.HasSubmission)
{
    Console.WriteLine("No submission has been completed for this period yet.");
    return;
}

if (!period.Accepted || !period.AcceptedFilesAvailable)
{
    Console.WriteLine($"Submission {period.SubmissionId} is {period.Status}; validation is {period.ValidationStatus}.");
    return;
}

var accepted = await client.GetAcceptedFilesByDeadlineAsync(feedSlug, deadlineAt);
Console.WriteLine($"{accepted.Files.Count} accepted file(s) are ready from {accepted.SubmissionId}.");
Paketi

Prijenos i preuzimanje više datoteka

Feedovi s više datoteka najbolje rade kada svaka očekivana datoteka ima slug datoteke feeda. U zahtjev za sesiju prijenosa uključite svaku datoteku, prenesite je na odredište koje API vrati, jednom dovršite predaju i zatim preuzmite sve prihvaćene datoteke za razdoblje kada DTO Flow prihvati predaju.

  • Koristite slugove datoteka feeda za strogo očekivane datoteke, poput prices ili inventory.
  • Koristite FeedFileSlug: null kada DTO Flow treba povezati jednu očekivanu datoteku prema nazivu ili za dopuštenu dodatnu datoteku. U poslovima s više datoteka koristite izričite slugove kako biste izbjegli nejasnoće.
  • Dovršite predaju nakon završetka svih prijenosa, ne nakon svake pojedinačne datoteke.
  • URL-ovi za preuzimanje vrijede kratko, zato za svako pokretanje zatražite svježe poveznice prihvaćenih datoteka.
Primjer koda

Prenesite i preuzmite razdoblje feeda s više datoteka

Isti obrazac radi za dvije datoteke ili veći skup očekivanih datoteka.

multi-file-sync.cs
using System.Globalization;
using System.Linq;
using DtoFlow.Integration;
using DtoFlow.Integration.Models;

var baseUrl = Environment.GetEnvironmentVariable("DTOFLOW_BASE_URL") ?? "https://api.dtoflow.com";
var token = Environment.GetEnvironmentVariable("DTOFLOW_TOKEN")
    ?? throw new InvalidOperationException("Set DTOFLOW_TOKEN.");
var feedSlug = Environment.GetEnvironmentVariable("DTOFLOW_FEED_SLUG") ?? "weekly-pack";
var deadlineAt = DateTimeOffset.Parse(
    Environment.GetEnvironmentVariable("DTOFLOW_DEADLINE_AT") ?? "2026-06-01T12:00:00Z",
    CultureInfo.InvariantCulture);
var downloadDirectory = Environment.GetEnvironmentVariable("DTOFLOW_DOWNLOAD_DIR") ?? "accepted";

var uploadFiles = new[]
{
    new { FeedFileSlug = "prices", Path = "incoming/prices.csv", ContentType = "text/csv" },
    new { FeedFileSlug = "inventory", Path = "incoming/inventory.xlsx", ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" },
};

using var httpClient = new HttpClient { BaseAddress = new Uri(baseUrl) };
var client = new DtoFlowAutomationClient(httpClient, token);

try
{
var session = await client.CreateUploadSessionAsync(
    feedSlug,
    deadlineAt,
    uploadFiles.Select(file =>
    {
        var fileInfo = new FileInfo(file.Path);
        return new CreateAutomationUploadFileRequest(
            file.FeedFileSlug,
            fileInfo.Name,
            file.ContentType,
            fileInfo.Length);
    }).ToArray());

var uploadTargets = session.Files.ToDictionary(
    file => file.OriginalFileName,
    StringComparer.OrdinalIgnoreCase);

foreach (var uploadFile in uploadFiles)
{
    var fileName = Path.GetFileName(uploadFile.Path);
    await using var stream = File.OpenRead(uploadFile.Path);
    await client.UploadFileAsync(uploadTargets[fileName], stream);
    Console.WriteLine($"Uploaded {fileName}.");
}

await client.CompleteUploadAsync(feedSlug, session.SubmissionId);

var period = await client.GetPeriodStatusByDeadlineAsync(feedSlug, deadlineAt);
if (!period.AcceptedFilesAvailable)
{
    Console.WriteLine($"Submission {session.SubmissionId} is {period.Status}; try download after validation completes.");
    return;
}

Directory.CreateDirectory(downloadDirectory);
var accepted = await client.GetAcceptedFilesByDeadlineAsync(feedSlug, deadlineAt);

foreach (var acceptedFile in accepted.Files)
{
    var destinationPath = Path.Combine(downloadDirectory, acceptedFile.FileName);
    await using var destination = File.Create(destinationPath);
    await client.DownloadAcceptedFileAsync(acceptedFile, destination);
    Console.WriteLine($"Downloaded {destinationPath}.");
}
}
catch (DtoFlowAutomationException ex) when (ex.IsTenantAccessReadOnly)
{
    Console.Error.WriteLine($"Tenant access is {ex.TenantAccessState}; required action: {ex.TenantAccessRequiredAction}.");
    Environment.ExitCode = 2;
}