Submit the order

Send the session ID to your server and submit the order to Teak.

When the customer completes checkout, your server tells Teak about the order. Teak then issues protection for every item the customer opted in to.

Submit the order after your own order is confirmed, for example after the customer's payment succeeds, so Teak never issues protection for an order that didn't go through.

1. Send the session ID with the order

Read the session ID from the widget and send it to your server along with the rest of the order:

// teakFailed is set in onErrorCb: see Handle the customer's choice
const sessionId = teakFailed ? null : teak.get('token');

await fetch('/checkout', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ ...order, teakSessionId: sessionId }),
});

Send the session ID whether the customer opted in or out: Teak works out from the session whether there's anything to issue. If the widget failed, send no session ID, and your server skips Submit for that order. See Errors.

2. Get an access token

On your server, exchange your API keys for an access token with Create an access token. Tokens expire after 5 minutes, so request one shortly before you submit rather than caching it.

const TEAK_API = 'https://api.sandbox.helloteak.com/v1';

async function getTeakToken() {
  const res = await fetch(`${TEAK_API}/auth/token`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      public_key: process.env.TEAK_PUBLIC_KEY,
      secret_key: process.env.TEAK_SECRET_KEY,
    }),
  });
  if (!res.ok) throw new Error(`Teak auth failed: ${res.status}`);
  return (await res.json()).token;
}
import os

import requests

TEAK_API = "https://api.sandbox.helloteak.com/v1"


def get_teak_token():
    res = requests.post(
        f"{TEAK_API}/auth/token",
        json={
            "public_key": os.environ["TEAK_PUBLIC_KEY"],
            "secret_key": os.environ["TEAK_SECRET_KEY"],
        },
        timeout=10,
    )
    res.raise_for_status()
    return res.json()["token"]
curl -X POST https://api.sandbox.helloteak.com/v1/auth/token \
  -H 'Content-Type: application/json' \
  -d '{"public_key": "pk_...", "secret_key": "sk_..."}'

3. Submit the order

Call Submit an order with the session ID in the path:

// order is your own order model
async function submitTeakOrder(sessionId, order) {
  if (!sessionId) return null;   // the widget failed: don't submit this order

  const token = await getTeakToken();
  const res = await fetch(`${TEAK_API}/orders/${sessionId}/submit`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      Authorization: `Bearer ${token}`,
    },
    body: JSON.stringify({
      reference_id: order.number,          // your order number, unique per order
      customer: {
        first_name: order.customer.firstName,
        last_name: order.customer.lastName,
        email: order.customer.email,
        phone: order.customer.phone,
      },
      billing_address: {
        address_1: order.billing.line1,
        address_2: order.billing.line2,
        city: order.billing.city,
        state: order.billing.state,
        country: order.billing.country,    // ISO code, e.g. "US"
        postal_code: order.billing.postalCode,
      },
      payment: { type: 'invoice' },
    }),
  });
  return res;
}
# order is your own order model
def submit_teak_order(session_id, order):
    if not session_id:
        return None  # the widget failed: don't submit this order

    res = requests.post(
        f"{TEAK_API}/orders/{session_id}/submit",
        headers={"Authorization": f"Bearer {get_teak_token()}"},
        json={
            "reference_id": order["number"],  # your order number, unique per order
            "customer": {
                "first_name": order["customer"]["first_name"],
                "last_name": order["customer"]["last_name"],
                "email": order["customer"]["email"],
                "phone": order["customer"]["phone"],
            },
            "billing_address": {
                "address_1": order["billing"]["line1"],
                "address_2": order["billing"]["line2"],
                "city": order["billing"]["city"],
                "state": order["billing"]["state"],
                "country": order["billing"]["country"],  # ISO code, e.g. "US"
                "postal_code": order["billing"]["postal_code"],
            },
            "payment": {"type": "invoice"},
        },
        timeout=10,
    )
    return res
curl -X POST https://api.sandbox.helloteak.com/v1/orders/3f1c9a2e-8b4d-4e6f-9a0b-1c2d3e4f5a6b/submit \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer <token>' \
  -d '{
    "reference_id": "ORD-1001",
    "customer": {"first_name": "Ada", "last_name": "Lovelace", "email": "[email protected]"},
    "billing_address": {"address_1": "100 Congress Ave", "city": "Austin", "state": "TX", "country": "US", "postal_code": "78701"},
    "payment": {"type": "invoice"}
  }'
FieldDescription
reference_idYour order number. It must be unique across your orders: Teak uses it to match webhooks and lookups to your order.
customerThe customer's name and email are required. Teak emails the customer their protection details.
billing_addressRecommended. Teak uses it to confirm where the customer is located.
paymentAlways { "type": "invoice" }. Teak bills you for issued protection on your regular invoice.

4. Handle the response

ResponseMeaningWhat to do
202 AcceptedTeak accepted the order and is issuing protection.Store the session_id with your order. Don't submit again.
204 No ContentThe customer didn't opt in to anything. No order was created.Nothing. This is a normal outcome.
400 with error.codeThe request couldn't be processed.See below.
401The access token is missing or expired.Request a new token and retry once.
403 with a detail messageTokenized orders aren't enabled for your account.Contact your Teak integration contact.
422 with a detail listA field is missing or has the wrong type.Fix the request.

Most errors return HTTP 400, with the specific error in error.code:

{
  "apiVersion": "2.0",
  "error": {
    "code": 404,
    "message": "invalid data. see errors for more information.",
    "errors": [
      {
        "domain": "Order",
        "reason": "NotFound",
        "message": "Session 3f1c9a2e-8b4d-4e6f-9a0b-1c2d3e4f5a6b not found"
      }
    ]
  }
}

Branch on error.code, not the HTTP status. It uses HTTP status meanings, for example 404 for not found, 409 for a conflict, and 503 for temporarily unavailable. errors[].reason gives a machine-readable reason, and errors[].message a human-readable one.

For Submit an order, error.code means:

error.codeMeaningWhat to do
403The session belongs to a different Teak account.Check your server uses the keys that match the widget's public key.
404The session doesn't exist.Check you're sending the session ID from the widget for this checkout.
409An order already exists for this session.Treat it as submitted. If you retried after a timeout, the first attempt succeeded.
422reference_id is already used by another order.Use a unique reference_id.
422Your account isn't set up for this product or billing type.Send payment as invoice, then contact your Teak integration contact.
503Teak is temporarily unavailable.Retry with backoff, for example after 1, 5, and 30 seconds.

The Submit an order reference has an example response for each. For when to retry, see Error handling.

For retries and error handling in one function, see the recipe:

The checkout example uses the same function, and submits in the background so checkout never waits on Teak.

Don't let a Teak error fail the customer's order

Their purchase is already complete. Log the error, retry where the table says to, and alert your team if it keeps failing.

Next steps

Orders are reaching Teak. Next, finish up after checkout:


Did this page help you?