Developer Documentation

Build with theShipToVerified REST API

Create verification sessions, embed our widget on your checkout, and listen for signed webhooks. Everything you need to ship a verified order.

Base URL https://api.shiptoverified.com

Developer-First Design

A small, predictable surface: REST + JSON, signed webhooks, and an embeddable widget.

RESTful Design

Clean, predictable URLs and standard HTTP methods. JSON in, JSON out.

Signed Webhooks

Real-time notifications with HMAC-SHA256 signatures and automatic retries with exponential backoff.

Embedded Widget

Ship a single JavaScript snippet and let your customers complete ID capture without leaving checkout.

Free 14-Day Trial

Every account starts with a 14-day free trial — verify real orders end-to-end before you commit.

Authentication

Every request to the public API requires two headers issued from your dashboard. The one exception is POST /api/v1/checkout/eligibility, which authenticates with the API key alone so a storefront can call it.

Required headers

  • X-API-Key — your merchant API key (e.g. vfy_live_xxxxx).
  • X-API-Secret — the paired secret. Treat like a password; never expose it client-side.
curl https://api.shiptoverified.com/api/v1/merchants/me \
  -H "X-API-Key: vfy_live_xxxxxxxxxxxxx" \
  -H "X-API-Secret: YOUR_API_SECRET"

Rotate compromised credentials from your dashboard, under Settings → Account → API keys. The previous pair is invalidated immediately.

Verification Endpoints

The core of the integration: create a verification, then drive it to completion.

POST/api/v1/verifications

Create a verification session for a customer order. The response includes a short-lived widget_token you can hand to the embedded widget on your storefront, and a verification_url you can send to the customer instead. Idempotent on transaction_id — a duplicate POST returns the existing verification (200) with a fresh token. Omit transaction_id to create a standalone verification with no order behind it.

// Request body
{
  "transaction_id": "ORD-12345",
  "customer_email": "customer@example.com",
  "target_name": "Jane Q. Buyer",
  "target_address": {
    "line1": "123 Main St",
    "city": "Los Angeles",
    "state": "CA",
    "postal_code": "90001",
    "country": "US"
  }
}

// 201 Created
{
  "id": "ver_abc123",
  "transaction_id": "ORD-12345",
  "status": "pending",
  "widget_token": "eyJhbGci...",
  "verification_url": "https://app.shiptoverified.com/verify/ver_abc123?token=eyJhbGci...",
  "created_at": "2025-01-15T18:04:11Z"
}
GET/api/v1/verifications/{id}

Retrieve the current state of a verification. Prefer webhooks over polling for completion notifications.

// 200 OK
{
  "id": "ver_abc123",
  "status": "verified",
  "name_match":    { "is_match": true,  "score": 0.95, "method": "fallback" },
  "address_match": { "is_match": true,  "score": 0.92, "method": "fallback" },
  "verified_name": "Jane Q. Buyer",
  "verified_at": "2025-01-15T18:07:42Z"
}
POST/api/v1/verifications/{id}/process

Submit the front of the customer’s ID document for OCR and matching. Supply either image_base64 or image_url.

// Request body — raw base64 only, no data: URI prefix
{
  "image_base64": "/9j/4AAQSkZJRg..."
}
POST/api/v1/verifications/{id}/secondary-proof

Submit a secondary proof of address (utility bill, lease, bank statement). Only valid when requires_secondary_proof is true.

POST/api/v1/verifications/{id}/use-id-name

Resolve a name mismatch by accepting the name extracted from the ID document.

POST/api/v1/verifications/{id}/use-id-address

Resolve an address mismatch by accepting the address extracted from the ID document.

POST/api/v1/verifications/{id}/acknowledge

Finalize a verification once name and address are resolved. Fires the verification.completed webhook and marks the verification verified.

DELETE/api/v1/verifications/{id}

Cancel a verification that has not completed (a verified one is refused with 400). The widget token can no longer be used to submit documents; fires the verification.cancelled webhook.

Merchant Endpoints

Read your merchant profile and manage settings programmatically. API credentials are rotated from the dashboard.

GET/api/v1/merchants/me

Return the merchant account that owns the API credentials in this request.

GET/api/v1/merchants/me/settings

Read non-sensitive merchant settings (branding, verification rules, notifications).

PATCH/api/v1/merchants/me/settings

Update merchant settings. Only fields included in the body are changed.

The public API also covers verification rules, exemptions, requesting secondary proof, checkout eligibility quotes, and fee reporting — see the full OpenAPI reference for every endpoint.

Verification Status Lifecycle

Every verification moves through a deterministic set of states.

pending

Verification created, awaiting an ID submission from the customer.

processing

An ID has been submitted and is being analyzed.

awaiting_action

A name/address mismatch needs to be resolved (use ID data, request secondary proof, etc.).

verified

Verification complete and acknowledged.

failed

Document could not be processed or verification could not be completed.

cancelled

Verification was cancelled by the merchant.

Webhooks

Set a webhook_url via PATCH /api/v1/merchants/me/settings and we'll POST signed events to it as verifications progress.

Events

  • verification.createdEmitted right after a verification is created — via the API, the dashboard, or a store integration when an order triggers verification.
  • verification.completedEmitted when the verification becomes verified — on acknowledgment, or automatically for a returning customer. Carries verified_name, verified_address, and updated_fields (the order fields the customer replaced with their ID values).
  • verification.failedEmitted when document processing ends in a terminal failure (e.g. the age check).
  • verification.cancelledEmitted when a verification is cancelled via DELETE /verifications/{id}, or when its order becomes exempt after the fact.

Headers we send

  • X-VerifyID-Event — event name (e.g. verification.completed).
  • X-VerifyID-Signature — t=<ts>,v1=<hmac_sha256(ts.payload, secret)>.
  • User-Agent — VerifyID-Webhook/1.0.

Example payload

{
  "event": "verification.completed",
  "timestamp": "2025-01-15T18:07:42+00:00",
  "verification_id": "ver_abc123",
  "transaction_id": "ORD-12345",
  "source": "order",
  "customer_id": "cus_4f12",
  "status": "verified",
  "verified_name": "Jane Q. Buyer",
  "verified_address": {
    "line1": "123 Main St", "city": "Los Angeles",
    "state": "CA", "postal_code": "90001", "country": "US"
  },
  "updated_fields": [],
  "verified_at": "2025-01-15T18:07:42+00:00",
  "method": "primary_id"
}

Delivery & retries

We retry non-2xx responses with backoff at 1 min, 5 min, 15 min, and 1 hr. Respond with any 2xx status within 30 seconds to acknowledge delivery. The signature is an HMAC-SHA256 keyed with the webhook_secret returned by GET /api/v1/merchants/me/settings — always verify it before trusting payload contents.

Widget Events

If you embed the widget without a backend webhook listener, subscribe to the same lifecycle in the browser with STV.on(...). Every detail carries orderId.

Reacting to a result

On verified, the detail includes verifiedName, verifiedAddress, and updatedFields — the order fields the customer replaced with their ID values ("name" and/or "address", or empty). Apply them to your order without diffing what you originally submitted.

<script src="https://api.shiptoverified.com/widget/v1.js"></script>
<script>
  STV.on("verified", function (d) {
    // d = { orderId, verifiedName, verifiedAddress, updatedFields }
    if (d.updatedFields.length) applyToOrder(d.verifiedName, d.verifiedAddress);
    releaseOrder();
  });
  STV.on("failed", function (d) { routeToManualReview(d.reason); });
  STV.on("error",  function (d) { console.error(d.message); });

  STV.init({ widgetToken: "WIDGET_TOKEN", orderId: "ORD-12345", apiUrl: "https://api.shiptoverified.com" });
</script>

Available events

  • mounted — the widget rendered its UI.
  • verified — identity verified; detail carries verifiedName, verifiedAddress, updatedFields.
  • failed — the customer did not pass; detail carries reason.
  • error — a technical failure (expired session, unreadable file); detail carries message.
  • address-review / address-updated / address-unverified — fire only in the standalone address-only (Radar) validation flow, not the ID flow.

Errors

Errors are returned as JSON with a detail field. Conventional HTTP status codes indicate the error class.

400

Verification is in a state that does not accept the requested action (e.g. processing an already-verified session).

401

Missing or invalid X-API-Key / X-API-Secret headers.

402

Your subscription is inactive. Reactivate billing before creating verifications.

404

Verification not found for this merchant.

409

The order is exempt from verification (you flagged it, or its address is on your exemption list). Nothing was created or charged — treat it as no verification needed.

422

Request body failed validation. Check detail for field-level errors.

500

Unexpected server error. Safe to retry with exponential backoff.

Quick Start

Create your first verification in three steps.

1. Get your API credentials

Sign up for a free dashboard account; your API key + secret appear under Settings → Account → API keys.

2. Create a verification

curl -X POST https://api.shiptoverified.com/api/v1/verifications \
  -H "X-API-Key: vfy_live_xxxxxxxxxxxxx" \
  -H "X-API-Secret: YOUR_API_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
    "transaction_id": "ORD-12345",
    "customer_email": "customer@example.com",
    "target_name": "Jane Q. Buyer",
    "target_address": {
      "line1": "123 Main St",
      "city": "Los Angeles",
      "state": "CA",
      "postal_code": "90001",
      "country": "US"
    }
  }'

3. Embed the widget

On your order-confirmation page, load the standalone bundle and hand it the widget_token from step 2 via STV.init(...). The widget walks the customer through ID capture; react to the result with STV.on(...) (see Widget Events) or the verification.completed webhook.

<!-- On your order-confirmation page -->
<div id="shiptoverified-widget"></div>
<script src="https://api.shiptoverified.com/widget/v1.js"></script>
<script>
  STV.init({
    widgetToken: "WIDGET_TOKEN_FROM_STEP_2",
    orderId: "ORD-12345",
    apiUrl: "https://api.shiptoverified.com",
  });
</script>

WooCommerce, BigCommerce, Magento, and Shopify merchants don't need to embed the script manually — install the ShipToVerified extension for your platform and the widget is injected for you.

Ready to Integrate?

Get your API keys and create your first verification today. Contact us if you want help wiring up your integration.