Tarifflo
  • Pricing
  • Refunds
  • IEEPA Refunds
Sign In

Get started

  • Overview
  • Authentication
  • Errors
  • Rate limits

Build

  • REST API
  • Webhooks
  • MCP connector
  • Entry shape

Help

  • Request a feature

Build

Webhooks

When an asynchronous job finishes, Tarifflo POSTs the result to the webhookUrl you passed with the request.

Where results go

There are no stored endpoints. Each request carries its own webhookUrl, and that job's result goes there. The URL must be public HTTPS; private and internal addresses are refused. If you omit it where it is optional, poll the job's GET endpoint instead.

Events

EventSent when
classification.completedA classification request finished
classification_batch.completedA bulk classification batch finished
tariff_rate.completedA tariff-rate lookup finished
pre_audit.completedAn audit intake run finished
export_control.completedAn export-control (ECCN) determination finished
origin.completedA rules-of-origin determination finished
entry.dispositionCBP answered an entry filed with POST /api/v1/entries

Payload

Every delivery has the same envelope. data is the same object the job's GET endpoint returns once it is complete.

Envelope
json
{
  "event": "tariff_rate.completed",
  "timestamp": "2026-10-23T14:23:45.123Z",
  "data": { "results": [ ... ] }
}
entry.disposition data
json
{
  "efid": "0193c1f2-...",
  "entryNumber": 1234567,
  "status": "APPROVED",
  "numActionItems": 0
}

Headers

X-Tarifflo-Event names the event. X-Tarifflo-Signature carries a timestamp and an HMAC-SHA256 of <timestamp>.<raw body>, keyed with your organization's webhook secret. Find the secret in the dashboard under Developers → Webhooks.

Request headers
http
Content-Type: application/json
X-Tarifflo-Event: tariff_rate.completed
X-Tarifflo-Signature: t=1761229425,sha256=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd

Verify the signature

Recompute the HMAC over the timestamp, a dot and the raw body, compare it in constant time, and reject timestamps older than five minutes so a captured delivery cannot be replayed.

Node.js
javascript
import crypto from "node:crypto";

// rawBody must be the exact bytes received, not re-serialized JSON.
export function verifyTarifflo(rawBody, signatureHeader, secret, toleranceSeconds = 300) {
    const parts = Object.fromEntries(signatureHeader.split(",").map((p) => p.split("=")));
    const timestamp = Number(parts.t);
    if (!timestamp || Math.abs(Date.now() / 1000 - timestamp) > toleranceSeconds) return false;

    const expected = crypto.createHmac("sha256", secret).update(`${parts.t}.${rawBody}`).digest("hex");
    const a = Buffer.from(expected);
    const b = Buffer.from(parts.sha256 ?? "");
    return a.length === b.length && crypto.timingSafeEqual(a, b);
}
Python
python
import hashlib, hmac, time

def verify_tarifflo(raw_body: bytes, signature_header: str, secret: str, tolerance: int = 300) -> bool:
    parts = dict(p.split("=", 1) for p in signature_header.split(","))
    ts = parts.get("t", "")
    if not ts.isdigit() or abs(time.time() - int(ts)) > tolerance:
        return False
    signed = ts.encode() + b"." + raw_body
    expected = hmac.new(secret.encode(), signed, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, parts.get("sha256", ""))

Retries

Answer with any 2xx within 10 seconds. A timeout, a network error, a 5xx, a 408 or a 429 is retried; any other 4xx is treated as a refusal and not retried. Deliveries can arrive more than once, so make your handler idempotent.

Tarifflo

AI-driven trade automation for modern importers and brokers.

Get started free

Platform

  • Audit
  • ABI Filing
  • PGA
  • Suppliers

Customs

  • HTS Classification
  • Schedule B
  • ECCN
  • Tariff Rates
  • Customs Clearance

Developers

  • Docs
  • REST API
  • Webhooks
  • MCP Connector

Product

  • Pricing
  • Refunds
  • IEEPA Refunds
  • Explore data

Company

  • FAQ
  • Contact Us
  • Book a Demo

© 2026 Tarifflo, Inc. All rights reserved.

Privacy PolicyTerms & Conditions