Authiflow

Integrate Authiflow

Authiflow is an independent product-verification layer between your shop and your customer. You connect once, flag the orders that need verification, ship them to the authentication center, and receive the verdict back on your own webhook. This guide has everything you need to integrate yourself — no help from us required.

Introduction

An order flagged with verification_required is sent to Authiflow. Instead of shipping straight to the customer, the item goes to the authentication center first. Our team inspects it and returns a verdict — passed, failed or needs review. Authiflow's only job is to give you an accurate, authenticated verdict; you decide what happens next in your own store.

The integration is a small set of JSON webhooks secured with a per-shop key pair. There is no SDK to install and no library to maintain — any language that can make an HTTPS request works.

How it works

  1. 1. Submit — you push a verification order to Authiflow. It lands as incoming. The response contains the center address (ship_to).
  2. 2. Ship to center — you send the product to the authentication center (not the customer) and optionally push the shipping status so the board follows it live.
  3. 3. Verify — the item is inspected at the center, within 2 working days.
  4. 4. Verdict — Authiflow POSTs the outcome to your feedback webhook. On a Pass it includes a link to an authenticity certificate.
  5. 5. Onward — you release the order to the customer (Pass) or handle a return (Fail). You are in control of fulfilment.

Getting started

  1. 1. Create an account at /register. You immediately receive a publicKey and secretKey.
  2. 2. Your account is reviewed and approved by Authiflow. Until it is approved your keys return 403 Account pending approval.
  3. 3. On the Integration page, set your feedback webhook URL + secret, your pickup address and your return address.
  4. 4. Start submitting orders (below) and handle the feedback webhook.

Keep your secretKey and feedbackSecret server-side only. You can rotate the key pair any time from the Integration page.

Authentication

Every inbound endpoint is authenticated with HTTP Basic auth using your key pair:

Authorization: Basic base64("<publicKey>:<secretKey>")

The Shopify ingestion endpoint is the one exception — Shopify's built-in webhooks can't send custom headers, so it also accepts the secret via the X-Api-Key header (preferred) or a ?token=<secretKey> query parameter.

Submit orders

POST /api/webhooks/orders

Submit an order that needs verification. Only verification_required: true is ingested. Idempotent on order_number — resubmitting the same order is safe.

POST https://authiflow.com/api/webhooks/orders
Authorization: Basic base64("<publicKey>:<secretKey>")
Content-Type: application/json

{
  "order_number": "10234",              // required — your order id, used everywhere
  "verification_required": true,        // required — only true is ingested

  "customer_name": "Jane Doe",
  "customer_email": "jane@example.com",
  "address_line1": "Keizersgracht 1",
  "address_line2": "",
  "postal_code": "1015 CJ",
  "city": "Amsterdam",
  "country": "Netherlands",

  "product_name": "Air Jordan 1 High OG Chicago",
  "sku": "555088-134",
  "size": "43",
  "product_category": "sneakers",
  "image_url": "https://yourshop.com/img/aj1.jpg",
  "seller_name": "Your Shop",

  "tracking_number": "3SABCD1234567",   // optional — your inbound label (shop → center)
  "tracking_url": "https://tracking.example.com/3SABCD1234567"
}

Response — 201 Created (or 200 if it already existed)

{
  "ok": true,
  "id": "clx8f...",
  "created": true,
  "ship_to": {
    "name": "Authiflow Authentication Center",
    "address_line1": "Voltastraat 51",
    "postal_code": "3335 KK",
    "city": "Zwijndrecht",
    "country": "Nederland",
    "country_code": "NL"
  }
}

If verification_required is not true, the order is ignored and you get { "ok": true, "skipped": true }. Send the shipment to the returned ship_to address — this is the core of the guarantee: the item is at the center, not with the customer, until it passes.

Shopify ingestion

POST /api/webhooks/shopify

Accepts a native Shopify order payload. Only orders tagged authiflow, verification, verification_required or verify are ingested — everything else is skipped. See the Shopify guide below for the full setup.

POST https://authiflow.com/api/webhooks/shopify
X-Api-Key: <secretKey>                 // preferred — or ?token=<secretKey>
Content-Type: application/json

<the Shopify order payload>

Response is the same shape as /api/webhooks/orders (with ship_to). Customer, address and line items are mapped from Shopify's payload automatically.

Shipping status

POST /api/webhooks/status

Push the shipping milestones so the board follows the parcel live. Two inbound milestones: shipped (label scanned / en route to the center) and received(delivered at the center → starts the 2 working-day verification SLA).

POST https://authiflow.com/api/webhooks/status
Authorization: Basic base64("<publicKey>:<secretKey>")
Content-Type: application/json

{
  "order_number": "10234",             // required
  "status": "shipped",                 // required — "shipped" | "received"
  "tracking_number": "3SABCD1234567",  // optional
  "tracking_url": "https://...",       // optional
  "occurred_at": "2026-07-01T10:00:00+02:00"  // optional — real milestone time (SLA start)
}

After a decision, the same endpoint records the outbound leg: send shipped once the parcel to the customer (after a Pass) or back to you (after a Fail) is really scanned — this advances the order to shipped_to_customer / returned_to_seller. Idempotent; an unknown order returns 404.

Cancellations & refunds

If an order is refunded or cancelled on your side before it reaches the center, push status: "cancelled" (also accepted: refunded, refund_processing) to the same endpoint — the order is then removed from Authiflow. This only works while the order is still incoming or shipped; once the item is at the verification center you get { ok: true, removed: false } back and we resolve the refund together.

POST https://authiflow.com/api/webhooks/status
Authorization: Basic base64("<publicKey>:<secretKey>")
Content-Type: application/json

{ "order_number": "10234", "status": "cancelled" }

// while incoming/shipped:      { "ok": true, "status": "cancelled", "removed": true }
// already at/past the center:  { "ok": true, "removed": false, "reason": "..." }

Shipping labels

POST /api/webhooks/label · multipart/form-data

Upload the customer label (after a Pass) or the return label (after a Fail) as a PDF so the center can print it. Optional tracking fields attach an informative track & trace to the card.

POST https://authiflow.com/api/webhooks/label
Authorization: Basic base64("<publicKey>:<secretKey>")
Content-Type: multipart/form-data

order_number    = 10234
label_type      = customer            // "customer" (after Pass) or "return" (after Fail)
label           = <the label as a PDF file>
tracking_number = 3SABCD1234567       // optional, informative
tracking_url    = https://...         // optional

The file must be a real PDF (415 otherwise). Re-uploading for the same order overwrites the previous label. An unknown order returns 404.

Center address

GET /api/center · public

The authentication center address as machine-readable JSON, if you want to generate the inbound label yourself. No authentication needed.

GET https://authiflow.com/api/center

{
  "authentication_center": {
    "name": "Authiflow Authentication Center",
    "address_line1": "Voltastraat 51",
    "postal_code": "3335 KK",
    "city": "Zwijndrecht",
    "country": "Nederland",
    "country_code": "NL"
  }
}

Feedback webhook

This is how you receive the verdict. On every status change, Authiflow POSTs to the feedback URL you set on the Integration page, signed with your feedbackSecret as a Bearer token. Verify that token, then act on status.

POST <your feedbackUrl>
Authorization: Bearer <feedbackSecret>
Content-Type: application/json

{
  "order_number": "10234",
  "status": "passed",                  // the Authiflow status — match on this
  "verification_status": "passed",     // mapped external code (optional to use)
  "status_label": "Passed",
  "tracking_number": "3SABCD1234567",
  "carrier_status": "Delivered at authentication center",
  "fail_reason": null,                 // set when status = failed
  "certificate_url": "https://authiflow.com/api/certificate/clx..?t=..",  // present on a Pass
  "source": "authiflow"
}

Respond with any 2xx. On a Pass, use certificate_urlin your customer email — it's a public, token-protected link to the authenticity certificate. If your endpoint was down, an order's current status can be re-sent from the dashboard.

Status reference

statusMeaning
incomingOrder received, awaiting shipment to the center.
shippedInbound label scanned / en route to the center.
in_verificationDelivered at the center; 2 working-day SLA running.
passedVerified authentic; certificate available.
failedDid not pass; fail_reason is set.
needs_reviewExtra check needed before a final verdict.
shipped_to_customerAfter a Pass, dispatched to the customer.
returned_to_sellerAfter a Fail, dispatched back to you.

Shipping & labels

There are three shipping legs:

  • Inbound (you → center): ship the product to the ship_to address before it reaches the customer. You can make this label yourself, or let Authiflow generate it from your pickup address.
  • Customer (→ customer, after a Pass): your own original label. Upload it via /api/webhooks/label (label_type=customer), or dispatch from your own system.
  • Return (center → you, after a Fail): upload a return label (label_type=return); otherwise a printable label to your configured return address is used.

Guide: Shopify

The simplest way to let customers choose verification is an add-on product plus Shopify Flow — no app development.

  1. 1. Create a service product "Premium Verification" (price = your fee; not a physical product, no inventory; SKU PREMIUM-VERIFY).
  2. 2. Let customers add it — a product/cart button (Cart AJAX /cart/add.js) or a free add-on app.
  3. 3. Flow A — on order created, if a line item SKU equals PREMIUM-VERIFY: add tag authiflow, action Hold fulfillment order, and an HTTP POST to https://authiflow.com/api/webhooks/shopify with header X-Api-Key: <secretKey>.
  4. 4. Flow B — on your feedback webhook with status = passed: Release fulfillment hold. On failed, keep it held and refund/return.
  5. 5. Ship the item to the center (a side-channel label, separate from Shopify's held fulfillment).

The fulfillment hold is placed by your Flow; Authiflow provides the verdict that releases it.

Guide: custom website

Three calls and a contract:

  1. 1. On checkout of a verification order, POST /api/webhooks/orders with verification_required: true and the customer/product fields.
  2. 2. Ship to the returned ship_to address — never to the customer yet. Optionally push /api/webhooks/status milestones.
  3. 3. On your feedback webhook: status = passed → release to the customer (add certificate_url to the email); anything else → hold/refund/return.

Errors

CodeMeaning
200 / 201Success. 201 when an order is created, 200 when it already existed.
400Invalid body or a missing required field.
401Missing or invalid API keys.
403Account pending approval — keys are valid but not yet activated.
404Unknown order_number (status / label). Submit the order first.
413 / 415Label too large / not a PDF.

Go-live checklist

  • Account approved by Authiflow (keys return 200, not 403).
  • Feedback URL + secret set; your endpoint verifies the Bearer token and returns 2xx.
  • Pickup address + return address set on the Integration page.
  • Orders submit with verification_required: true and land as incoming.
  • You ship to ship_to, not the customer, and push shipped / received.
  • Your system reacts to passed / failed / needs_review from the feedback webhook.
  • (Shopify) Flow A holds fulfillment on the tag; Flow B releases it only on passed.

Questions during integration? Reach us at support@authiflow.com.