Support

DTO Flow help center

Practical guidance for launching partner file exchanges, helping partners succeed, connecting systems, and getting support when you need it.

Integration

Webhooks

Use webhooks when another system needs to react after DTO Flow receives, validates, accepts, or misses a recurring partner file.

Explore webhook delivery for partner-file eventsSee how webhook activity remains accountable
Setup

Subscriptions

A webhook subscription connects one DTO Flow event stream to one receiver endpoint. Create separate subscriptions for separate destinations, environments, or ownership boundaries so each integration can be tested, paused, rotated, and reviewed independently.

  • Use a stable HTTPS endpoint in production, such as https://example.com/webhooks/dtoflow.
  • Choose whether the subscription applies to all feeds or only selected file feeds.
  • Subscribe only to the events the receiver needs, then narrow completed-submission events by status when the receiver only cares about accepted, rejected, or failed submissions.
  • Store the signing secret immediately; DTO Flow shows the raw secret when it is created or rotated.
  • Send a test delivery before enabling a downstream import or alert workflow.
  • Review delivery history when an endpoint returns errors, times out, or is paused.

Manage subscriptions in the signed-in DTO Flow app. Private access tokens authenticate file-automation APIs; they do not create or manage webhook subscriptions.

Delivery

Delivery Behavior

DTO Flow sends each delivery as an HTTP POST with a JSON body. Verify the signature against the raw request body, persist or enqueue the follow-up work, and return a 2xx response promptly, then handle longer follow-up after acknowledging it.

  • Deliveries include Content-Type: application/json and User-Agent: DTO Flow Webhooks/1.0.
  • A 2xx response marks the delivery sent. Non-2xx responses, timeouts, and transport failures are recorded in delivery history.
  • DTO Flow makes up to six delivery attempts for transient failures. Delays before attempts two through six are 5 minutes, 10 minutes, 30 minutes, 1 hour, and 2 hours.
  • Test deliveries are sent once so failed tests do not keep retrying while you debug.
  • Use DTOFlow-Event-Id and DTOFlow-Delivery-Id for idempotency and delivery tracking.
  • Do not rely on delivery order when multiple submissions, feeds, or retries are active.
Events

Event Payloads

Payloads are intentionally compact. They include stable IDs, feed and partner context, period dates, submission status, validation status, submitted-file summaries, and deadline details when the event is about a missed period.

feed.submission.available
Sent when a submission is the current accepted submission for its feed, partner, and period. Use this event to start an import or retrieve the accepted original through an authorized path.
feed.submission.completed
Sent when a submission reaches a terminal status such as Validated, ValidationFailed, Delivered, DeliveryFailed, Rejected, or Archived. Status filters can narrow which completed submissions notify the endpoint.
feed.period.deadline_elapsed
Sent when the deadline check concludes that the expected period has elapsed without a completed submission.
webhook.test
Sent by a manual test delivery so you can verify routing, signature checks, logs, and alert handling before real file events are enabled.

Signature headers are DTOFlow-Timestamp and DTOFlow-Signature-256. The examples verify the HMAC signature over timestamp.rawBody and reject timestamps outside the default five-minute replay window.

Code sample

Example webhook payload

The exact populated fields depend on the event type and submission state.

feed-submission-available.json
{
  "schemaVersion": 1,
  "eventId": "75c789c2-e5bb-4a7e-95cc-6ee78481ec8b",
  "eventType": "feed.submission.available",
  "occurredAt": "2026-06-01T12:04:31Z",
  "tenantId": "f6398077-653b-42fa-99af-2de4aca395c2",
  "tenantName": "Contoso Retail",
  "fileFeedId": "5306fb96-fb40-41d1-baa3-5d27922c5ea1",
  "fileFeedName": "Supplier Prices",
  "partnerId": "088cb758-a819-4116-9c91-d4f8bd59eb36",
  "partnerName": "Northwind Foods",
  "submissionId": "5dfc82ed-4d7d-42e2-9d90-580d0b36f0ee",
  "periodKey": "2026-06",
  "periodStart": "2026-06-01T00:00:00Z",
  "periodEnd": "2026-06-30T23:59:59Z",
  "dueAt": "2026-06-01T12:00:00Z",
  "overallStatus": "Validated",
  "overallValidationStatus": "Passed",
  "isCurrentAcceptedSubmission": true,
  "files": [
    {
      "fileId": "6022d3fd-c236-4672-ad9b-eb16f29eeff8",
      "feedFileId": "c067c23a-8a34-4131-bb3d-e77bd65d034a",
      "feedFileName": "Prices",
      "originalFileName": "prices.csv",
      "status": "Validated",
      "validationStatus": "Passed",
      "errorCount": 0,
      "warningCount": 2,
      "infoCount": 4,
      "sizeBytes": 18422,
      "contentType": "text/csv",
      "contentHash": "sha256:9d3f..."
    }
  ],
  "deadline": null
}
Examples

Receiver Examples

Start with one receiver route that verifies the signature, parses the event, ignores unknown event types safely, and queues slower work outside the request cycle.

  • Notify an external system when a partner file becomes the current accepted submission.
  • Start an internal import after validation succeeds.
  • Open an operations task when a completed submission failed validation or delivery.
  • Record a missed-period alert when no completed file arrived before the deadline.

.NET reference: the .NET tab previews DtoFlow.Integration types. The sample classes, including DtoFlowWebhookVerifier, DtoFlowWebhookHeaders, and DtoFlowWebhookEventCodes, illustrate the client shape. Build current integrations with the raw HTTP example and the published OpenAPI contract.

Code sample

Verify a DTO Flow webhook delivery

Always verify the signature against the raw request body before parsing JSON.

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

var builder = WebApplication.CreateBuilder(args);
var signingSecret = builder.Configuration["DTOFLOW_WEBHOOK_SECRET"]
    ?? throw new InvalidOperationException("Set DTOFLOW_WEBHOOK_SECRET.");

var app = builder.Build();

app.MapPost("/webhooks/dtoflow", async (HttpRequest request) =>
{
    request.EnableBuffering();

    using var buffer = new MemoryStream();
    await request.Body.CopyToAsync(buffer);
    var rawBody = buffer.ToArray();
    request.Body.Position = 0;

    var headers = DtoFlowWebhookHeaders.FromHeaderLookup(
        name => request.Headers[name].ToString());
    var verification = DtoFlowWebhookVerifier.Verify(rawBody, headers, signingSecret);

    if (!verification.IsValid)
    {
        app.Logger.LogWarning(
            "Rejected DTO Flow webhook delivery {DeliveryId}: {ErrorCode}.",
            headers.DeliveryId,
            verification.ErrorCode);

        return Results.Unauthorized();
    }

    if (!DtoFlowWebhookVerifier.TryDeserializePayload(rawBody, out var payload) ||
        payload is null)
    {
        return Results.BadRequest();
    }

    var eventCode = DtoFlowWebhookEventCodes.Parse(payload.EventType);
    switch (eventCode)
    {
        case DtoFlowWebhookEventCode.FeedSubmissionAvailable:
            QueueImport(payload);
            break;

        case DtoFlowWebhookEventCode.FeedPeriodDeadlineElapsed:
            AlertOperations(payload);
            break;

        case DtoFlowWebhookEventCode.Unknown:
            app.Logger.LogInformation("Ignored unknown DTO Flow event {EventType}.", payload.EventType);
            break;
    }

    return Results.Ok();
});

app.Run();

static void QueueImport(DtoFlowWebhookPayload payload)
{
    if (payload.SubmissionId is null || payload.IsCurrentAcceptedSubmission != true)
    {
        return;
    }

    Console.WriteLine($"Queue import for submission {payload.SubmissionId}.");
}

static void AlertOperations(DtoFlowWebhookPayload payload)
{
    Console.WriteLine($"Deadline elapsed for {payload.FileFeedName}: {payload.PeriodKey}.");
}
Reference

Webhook Receiver Reference

Receiver code needs signature verification, safe payload parsing, and event-code handling. The .NET tab shows a reference shape for the same behavior.

DtoFlowWebhookVerifier.Verify(...)
Verifies DTOFlow-Timestamp and DTOFlow-Signature-256 against the raw body and signing secret.
DtoFlowWebhookVerifier.TryDeserializePayload(...)
Safely parses the JSON payload into DtoFlowWebhookPayload without throwing on malformed JSON.
DtoFlowWebhookEventCodes.Parse(...)
Maps event names such as feed.submission.completed to stable enum-style values so receiver code can use a clear switch statement.
DtoFlowSubmissionStatusCodes.Parse(...)
Parses submission status values such as Validated, ValidationFailed, and DeliveryFailed.
Code sample

Route verified webhook events

Use the receiver examples to verify, parse, and route webhook events safely.

route-dtoflow-event.cs
using DtoFlow.Integration;
using DtoFlow.Integration.Models;

static void HandleDtoFlowEvent(DtoFlowWebhookPayload payload)
{
    var eventCode = DtoFlowWebhookEventCodes.Parse(payload.EventType);
    var submissionStatus = DtoFlowSubmissionStatusCodes.Parse(payload.OverallStatus);
    var validationStatus = DtoFlowValidationStatusCodes.Parse(payload.OverallValidationStatus);

    switch (eventCode)
    {
        case DtoFlowWebhookEventCode.FeedSubmissionCompleted:
            if (submissionStatus == DtoFlowSubmissionStatusCode.ValidationFailed)
            {
                Console.WriteLine($"Submission {payload.SubmissionId} failed validation.");
            }

            if (validationStatus == DtoFlowValidationStatusCode.Passed)
            {
                Console.WriteLine($"Submission {payload.SubmissionId} passed validation.");
            }
            break;

        case DtoFlowWebhookEventCode.FeedSubmissionAvailable:
            foreach (var file in payload.Files)
            {
                var fileStatus = DtoFlowSubmittedFileStatusCodes.Parse(file.Status);
                Console.WriteLine($"{file.OriginalFileName}: {fileStatus}, errors={file.ErrorCount}");
            }
            break;

        case DtoFlowWebhookEventCode.FeedPeriodDeadlineElapsed:
            var outcome = DtoFlowDeadlineOutcomeCodes.Parse(payload.Deadline?.Outcome);
            Console.WriteLine($"Deadline event {outcome} for period {payload.PeriodKey}.");
            break;
    }
}