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 rescurl -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"}
}'| Field | Description |
|---|---|
reference_id | Your order number. It must be unique across your orders: Teak uses it to match webhooks and lookups to your order. |
customer | The customer's name and email are required. Teak emails the customer their protection details. |
billing_address | Recommended. Teak uses it to confirm where the customer is located. |
payment | Always { "type": "invoice" }. Teak bills you for issued protection on your regular invoice. |
4. Handle the response
| Response | Meaning | What to do |
|---|---|---|
202 Accepted | Teak accepted the order and is issuing protection. | Store the session_id with your order. Don't submit again. |
204 No Content | The customer didn't opt in to anything. No order was created. | Nothing. This is a normal outcome. |
400 with error.code | The request couldn't be processed. | See below. |
401 | The access token is missing or expired. | Request a new token and retry once. |
403 with a detail message | Tokenized orders aren't enabled for your account. | Contact your Teak integration contact. |
422 with a detail list | A 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.code | Meaning | What to do |
|---|---|---|
403 | The session belongs to a different Teak account. | Check your server uses the keys that match the widget's public key. |
404 | The session doesn't exist. | Check you're sending the session ID from the widget for this checkout. |
409 | An order already exists for this session. | Treat it as submitted. If you retried after a timeout, the first attempt succeeded. |
422 | reference_id is already used by another order. | Use a unique reference_id. |
422 | Your account isn't set up for this product or billing type. | Send payment as invoice, then contact your Teak integration contact. |
503 | Teak 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.
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:
- Finish up after checkout: reset the widget, confirm protection was issued, and give the customer their links.
- Learn how to handle errors from every endpoint, and when to retry.
Updated 19 days ago
