Orval react-query client from the Sume OpenAPI JSON, tags-split

Point Orval at api.sume.com/reference/json with client react-query and mode tags-split for typed hooks per Sume tag. Config, caveats and polling tips.

5 min readSume
All posts

The short answer

Orval's documentation shows a config with client: 'react-query', mode: 'tags-split' and an input.target pointing at an OpenAPI file. Change that target to Sume's live spec at https://api.sume.com/reference/json and Orval generates one custom hook per path, grouped by tag.

The generated hooks make the requests; they do not know which Sume calls are paid. You still choose async mode, send an Idempotency-Key on creates, and decide when polling stops.

The config

This follows the shape on Orval's home page, with the input swapped. Save it as orval.config.ts and run Orval from the project root.

import { defineConfig } from 'orval';

export default defineConfig({
  sume: {
    input: {
      target: 'https://api.sume.com/reference/json',
    },
    output: {
      mode: 'tags-split',
      target: 'src/api/sume.ts',
      schemas: 'src/api/model',
      client: 'react-query',
    },
  },
});

What you get and what you should check

Orval describes generating one hook per path, each with a query key helper. For a spec with 183 operations that is a lot of surface, and tags-split keeps it manageable by splitting output per tag; Sume tags its job endpoints under Jobs, so those land together.

Two spec facts matter for the types. The document is OpenAPI 3.0.3, and the job status schema marks next_poll_after_seconds as nullable, because a terminal job has nothing left to poll. Check that your generated type allows null before you compute a refetchInterval from it.

Orval options used here (read 2026-10-03)
OptionValueEffect
clientreact-queryGenerates query hooks and key helpers
modetags-splitSplits generated files by OpenAPI tag
schemassrc/api/modelWrites the model types to their own folder
input.targetSume reference JSONRegenerate to pick up spec changes

Polling with the generated hook

The status hook accepts normal TanStack Query options. Return false from refetchInterval once terminal is true, and otherwise return the delay Sume suggests, multiplied by 1000. That keeps the poll rate under the server's guidance and stops it the moment the job is done. Our React Query polling post covers the same idea with a hand-written hook.

Regenerate on a schedule, not on every build

The live spec changes when Sume adds endpoints. Fetching it on every build makes builds depend on the network and can introduce diffs you did not review. Download the JSON, commit it, and point Orval at the file; refresh it deliberately and review the generated diff. The client guide lists the other generators you can run against the same document.

Sending the headers Orval does not know about

A generated hook calls your HTTP client, so credentials and the Idempotency-Key header belong in the client layer or in the per-call options. Put the Bearer token in a request interceptor that reads it from server-side configuration, and never ship a workspace key to a browser bundle; route browser calls through your own backend instead.

For creates, pass the key in the call options from a value your code derives from the user's intent, such as the order and a revision counter. The same key on a retry returns the original job, and the response's idempotency_hit field tells you it happened.

Finally, treat the error type with care. Sume answers 402 insufficient_credits, 413 payload_too_large and two different 429 codes, rate_limited and queue_full. Only the first of those 429s is a plain back-off case; the second means workspace capacity is full.

Sources

Related posts

More in Developers

All Developers posts

Written by Sume