Capxul Docs
HooksMedia

useCapxulImageUpload

Mutation hook that uploads an image blob and binds it as the profile image or an organization logo in one step.

Uploads an image and records it as the signed-in user's profile image or an organization logo — the whole upload → record sequence as one mutation. The resolved serving URL then appears on useCapxulProfile (imageUrl) or on the organization read (logoUrl).

Serving URLs are not stable links

The returned url is resolved at read time and is not a long-lived stable link. Re-read it from the profile or organization queries; do not persist it.

Import

import { useCapxulImageUpload } from "@capxul/sdk-react";

Usage

"use client";

import { useCapxulImageUpload } from "@capxul/sdk-react";

function ProfileImagePicker() {
  const upload = useCapxulImageUpload();

  return (
    <input
      type="file"
      accept="image/jpeg,image/png,image/webp"
      disabled={upload.isPending}
      onChange={(event) => {
        const file = event.target.files?.[0];
        if (file) upload.mutate({ blob: file, target: { kind: "profile" } });
      }}
    />
  );
}

For an organization logo, pass target: { kind: "orgLogo", orgId }. Recording a logo requires spend authority in that organization, and replacing an image deletes the previously stored blob.

Parameters

The hook itself takes no parameters. The mutation takes an ImageUploadInput:

FieldTypeDescription
blobBlobThe image bytes; the blob's MIME type is sent as the upload content type.
target{ kind: "profile" } | { kind: "orgLogo"; orgId: string }What the uploaded image becomes.

The backend recording mutation is the validation boundary: the blob must declare a image/jpeg, image/png, or image/webp content type and be at most 5 MB.

Return type

import { type UseCapxulImageUploadReturn } from "@capxul/sdk-react";
// UseMutationResult<{ url: string | null }, CapxulError, ImageUploadInput>

On success, data.url is the resolved serving URL for the recorded image.

The hook returns TanStack Query's UseMutationResult. The most-used fields:

FieldDescription
mutateFire the mutation (fire-and-forget; pair with onSuccess/onError callbacks).
mutateAsyncFire the mutation and get a Promise of the result. Rejects with a CapxulError on failure.
dataThe mutation result (typed per hook, shown above). undefined until the first success.
errorA CapxulError when the last attempt failed, otherwise null.
isPendingtrue while the mutation is in flight. Use it to disable submit buttons.
resetClear the mutation state (data, error) back to idle.

Mutations do not retry by default. The full field list is in the TanStack Query useMutation reference; see also the TanStack Query integration guide.

Client-backed mutation hooks are safe to render while CapxulProvider bootstraps. If one is fired before bootstrap finishes, mutateAsync rejects with a CapxulError whose code is WRONG_STATE; applications do not need to hide their route tree behind useCapxul(). Every shipped mutation hook is client-backed — alpha.23 removed the one client-free hook (useCapxulSwitchActingEntity, a documented no-op).

Cache behavior

On success this mutation invalidates the profile query (["capxul", "profile"]) for a profile image, or every organizations query (the ["capxul", "orgs"] prefix) for a logo.

Errors

Failures surface as a CapxulError on error / thrown from mutateAsyncINVALID_INPUT when the blob is not an accepted image type or exceeds 5 MB, a provider error when the upload POST itself fails, and NOT_AUTHENTICATED / authority errors when the caller does not own the target profile or lacks spend authority in the target organization.

Client method

This hook wraps client.media.uploadImage(blob) followed by client.media.setProfileImage({ storageId }) or client.media.setOrgLogo({ orgId, storageId }) on the core SDK.

On this page