createSumeClient sends x-api-key only: an extra header gives 401

The Sume API accepts Bearer or x-api-key but rejects both at once with 401. A fetch wrapper for createSumeClient that drops the extra header, tested offline.

4 min readSume
All posts

createSumeClient sends the x-api-key header and nothing else. If a gateway, proxy, or interceptor also adds Authorization: Bearer ..., the Sume API fails the request with 401 unauthorized and the message Send only one API key credential. There is no precedence rule; neither header wins. Remove one of them in a custom fetch wrapper.

What the API accepts

The Authentication and SDK pages agree on the rules.

Credential headers and outcomes (Sume docs, read 2026-10-09)
Request carriesOutcome
Authorization: Bearer onlyAccepted
x-api-key onlyAccepted
Both401 unauthorized: Send only one API key credential.
Neither, or a revoked key401 unauthorized

A wrapper that keeps one

The SDK's fetch option lets you supply your own function. This wrapper deletes Authorization whenever x-api-key is present. The block at the bottom checks the wrapper offline with a fake fetch, so it prints false true without calling Sume. I ran it with Bun.

import { createSumeClient } from "@sume-com/sdk";

// Some gateways add `Authorization` to every outgoing request. The SDK already
// sends `x-api-key`, and the API rejects both together with 401.
const oneCredential: typeof fetch = (input, init) => {
  const headers = new Headers(init?.headers ?? (input instanceof Request ? input.headers : undefined));
  if (headers.has("x-api-key")) headers.delete("authorization");
  return globalThis.fetch(input, { ...init, headers });
};

export const client = createSumeClient({
  apiKey: process.env.SUME_API_KEY ?? "missing",
  fetch: oneCredential,
});

// Offline check of the wrapper itself:
const seen: Headers[] = [];
globalThis.fetch = (async (_i: RequestInfo | URL, init?: RequestInit) => {
  seen.push(new Headers(init?.headers));
  return new Response("{}");
}) as typeof fetch;
const sent = new Headers({ "x-api-key": "k", Authorization: "Bearer other" });
await oneCredential("https://api.sume.com/v1/me", { headers: sent });
console.log(seen[0].has("authorization"), seen[0].has("x-api-key")); // false true

Where the extra header comes from

The docs name the usual sources: a session token, the credential of a gateway, or an interceptor that you forgot. The problem shows only on a wrapped client, which is why a plain curl with the same key works and the app does not.

If you do not use the SDK, pick one header and use it consistently. Keep the key on the server. There is no browser-safe variant, so never put it in client JavaScript or a NEXT_PUBLIC_* variable; call your own endpoint, which attaches the key.

Debugging checklist

When a call works from curl and fails from the app, print the outgoing headers at the last hop. Look for Authorization added by an HTTP client default, a corporate proxy, or an SDK for another service sharing the same fetch.

The error text is explicit, so match on it in logs. A 401 with a different message means the key is missing, revoked or malformed.

Sources

Related posts

More in Developers

All Developers posts

Written by Sume