Async polling and webhooks
DGII confirms e-CFs asynchronously via a trackId. ERPly Pro abstracts this pattern for you.
Polling
curl https://sandbox.api.erply.pro/v1/invoices/{docId}/status \
-H "Authorization: Bearer $ERPLYPRO_API_KEY"
{
"docId": "01HW9X4G…",
"trackId": "20260501-DGII-9988",
"status": "accepted",
"dgii": { "approvedAt": "2026-05-01T17:42:11Z" }
}
Webhook
ERPly Pro sends a POST to the tenant's configured webhook:
POST /tu-webhook HTTP/1.1
Content-Type: application/json
X-ErplyPro-Event: invoice.accepted
X-ErplyPro-Signature: t=1714583811,v1=4f9d…
X-ErplyPro-Delivery: 01HW9X4G…
Verify the signature (constant-time) using the shared secret:
import hmac, hashlib, time
def verify(body: bytes, header: str, secret: bytes, *, max_skew=300) -> bool:
parts = dict(p.split("=") for p in header.split(","))
t = int(parts["t"])
if abs(time.time() - t) > max_skew:
return False
expected = hmac.new(secret, f"{t}.".encode() + body, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, parts["v1"])
Retries
ERPly Pro retries the webhook with exponential back-off (1s/4s/16s/64s/256s) up to 5 attempts. If they all fail, the event is parked in a DLQ and the operator is paged via PagerDuty.