Skip to main content

Customers

Customers are the end users tracked in Tether. Use this endpoint to upsert customers by email or external ID.

The customer object

1{
2  "tether_id": "3f4e2b1a-...",
3  "external_id": "cus_abc123",
4  "email": "jane@acme.com",
5  "name": "Jane Doe",
6  "company_name": "Acme Corp",
7  "stripe_customer_id": "cus_stripe123",
8  "mrr": 99,
9  "subscription_status": "active",
10  "auto_renew": true,
11  "period_end": "2026-12-31T00:00:00Z",
12  "last_activity": "2026-04-01T09:00:00Z",
13  "created_at": "2025-01-15T10:00:00Z",
14  "updated_at": "2026-04-01T08:30:00Z"
15}
NameTypeRequiredDescription
tether_idstring (UUID)optionalTether's internal identifier for this customer. Stable and unique across your account.
external_idstring | nulloptionalYour own system's identifier for this customer. Set on upsert; use with X-Customer-Id-Type: external for lookups.
emailstringoptionalThe customer's email address (always lowercase).
namestring | nulloptionalFull name.
company_namestring | nulloptionalCompany or organization name.
stripe_customer_idstring | nulloptionalStripe customer ID. Set automatically when Tether is connected to Stripe. Read-only via the API.
mrrnumber | nulloptionalMonthly recurring revenue in your account's currency.
subscription_statusstring | nulloptionalSubscription state. Common values: "active", "trialing", "past_due", "canceled".
auto_renewboolean | nulloptionalWhether the subscription renews automatically at period end.
period_endstring | null (ISO 8601)optionalEnd date of the current billing period.
last_activitystring | null (ISO 8601)optionalTimestamp of the customer's last known activity.
created_atstring (ISO 8601)optionalWhen the customer was added to Tether.
updated_atstring (ISO 8601)optionalWhen the customer record was last modified.

The X-Customer-Id-Type header

Several endpoints accept a customer identifier in the URL or request body. The X-Customer-Id-Type header tells Tether which identifier you are using:

NameTypeRequiredDescription
emailheader valueoptionalLook up the customer by email address. This is the default when the header is omitted.
externalheader valueoptionalLook up the customer by your own system's ID, stored in the external_id field. Falls back to email lookup if no match is found.

Upsert a customer

POST/api/v1/customers

Creates or updates a customer. Tether looks up the customer using the identifier you provide — if found, it updates the record; if not found, it creates a new one (when creation is enabled for the product).

Requires a product-scoped API key. The key determines which product the customer belongs to.

Lookup behavior

The X-Customer-Id-Type header controls how Tether matches an existing customer:

  • email (default) — matches on the email field only.
  • external — matches on external_id first; if no match, falls back to email.

Customer creation gate

By default, the upsert endpoint will not create new customers — it will only update existing ones. To enable creation, go to Settings → Products → [product] → API and toggle Allow customer creation via API.

When creation is disabled and no matching customer is found, the API returns 422 CREATION_DISABLED.

Request body

At least one of email or external_id is required.

NameTypeRequiredDescription
emailstringoptionalCustomer email. Required when creating a new customer.
external_idstringoptionalYour system's identifier for this customer.
namestringoptionalFull name.
company_namestringoptionalCompany or organization name.
mrrnumberoptionalMonthly recurring revenue.
subscription_statusstringoptionalSubscription state. Example: "active", "canceled".
auto_renewbooleanoptionalWhether the subscription renews automatically.
period_endstring (ISO 8601)optionalCurrent billing period end date.
last_activitystring (ISO 8601)optionalLast known activity timestamp for this customer.

Example request

async function request(data: Record<string, unknown>) {
  const response = await fetch("https://usetether.io/api/v1/customers", {
    method: "POST",
    headers: {
      Authorization: `Bearer ${import.meta.env.VITE_TETHER_API_KEY}`,
      "X-Customer-Id-Type": "external",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      email: "jane@acme.com",
      external_id: "cus_abc123",
      name: "Jane Doe",
      mrr: 99,
      subscription_status: "active",
}),
  });
  return response.json();
}

Response — created (201)

1{
2  "action": "created",
3  "customer": {
4    "tether_id": "3f4e2b1a-...",
5    "external_id": "cus_abc123",
6    "email": "jane@acme.com",
7    "name": "Jane Doe",
8    "company_name": null,
9    "stripe_customer_id": null,
10    "mrr": 99,
11    "subscription_status": "active",
12    "auto_renew": null,
13    "period_end": null,
14    "last_activity": null,
15    "created_at": "2026-04-20T12:00:00Z",
16    "updated_at": "2026-04-20T12:00:00Z"
17  },
18  "health_score": 74
19}

Response — updated (200)

1{
2  "action": "updated",
3  "customer": {
4    "tether_id": "3f4e2b1a-...",
5    "external_id": "cus_abc123",
6    "email": "jane@acme.com",
7    "name": "Jane Doe",
8    "company_name": null,
9    "stripe_customer_id": null,
10    "mrr": 99,
11    "subscription_status": "active",
12    "auto_renew": null,
13    "period_end": null,
14    "last_activity": null,
15    "created_at": "2025-01-15T10:00:00Z",
16    "updated_at": "2026-04-20T12:00:00Z"
17  },
18  "health_score": 74
19}

Error — creation disabled (422)

1{
2  "error": "Customer not found and customer creation via API is disabled for this product. Enable it in Settings → Products → [product] → API.",
3  "code": "CREATION_DISABLED"
4}