uploadcare-ruby is a framework-agnostic client for the Uploadcare Upload API and REST API.
The gem is built around:
explicit
Uploadcare::Clientinstancesclient-scoped configuration for multi-account use
a small convenience layer for common workflows
full endpoint coverage through
client.api.restandclient.api.upload
- Ruby 3.3+
This gem is intended for plain Ruby applications and for framework integrations built on top of it.
- Use explicit
Uploadcare::Clientinstances when you need multiple accounts in one process. - Use
Uploadcare.configureandUploadcare.clientwhen one global default client is enough. - Use
client.api.restandclient.api.uploadwhen you want endpoint-level parity with the official API references.
Add the gem to your Gemfile:
gem"uploadcare-ruby"Then install:
bundleSet credentials with environment variables:
export UPLOADCARE_PUBLIC_KEY=your_public_key
export UPLOADCARE_SECRET_KEY=your_secret_keyThe gem has two public layers:
This is the default API you should use in applications:
client.filesclient.groupsclient.uploadsclient.projectclient.webhooksclient.file_metadataclient.addonsclient.conversions
This layer returns resources and collections, and it raises typed exceptions on failure.
This layer mirrors Uploadcare’s REST and Upload APIs:
client.api.restclient.api.upload
This layer returns Uploadcare::Result objects so you can inspect success and failure explicitly.
That split keeps app code clean without losing full API coverage.
require"uploadcare"client=Uploadcare::Client.new(public_key: ENV.fetch("UPLOADCARE_PUBLIC_KEY"),secret_key: ENV.fetch("UPLOADCARE_SECRET_KEY"))file=File.open("photo.jpg","rb")do |io|
client.files.upload(io,store: true)endputsfile.uuidputsfile.cdn_urlYou can also configure a default global client:
Uploadcare.configuredo |config|
config.public_key=ENV.fetch("UPLOADCARE_PUBLIC_KEY")config.secret_key=ENV.fetch("UPLOADCARE_SECRET_KEY")endfile=File.open("photo.jpg","rb")do |io|
Uploadcare.files.upload(io,store: true)endThe recommended style is explicit Uploadcare::Client instances. Global configuration is best treated as a default.
This is the shortest end-to-end flow for the main public API:
require"uploadcare"client=Uploadcare::Client.new(public_key: ENV.fetch("UPLOADCARE_PUBLIC_KEY"),secret_key: ENV.fetch("UPLOADCARE_SECRET_KEY"))file=File.open("photo.jpg","rb")do |io|
client.files.upload(io,store: true)endgroup=client.groups.create(uuids: [file.uuid])putsfile.uuidputsfile.cdn_urlputsgroup.idputsgroup.cdn_urlUse Uploadcare.configure to set process-wide defaults:
Uploadcare.configuredo |config|
config.public_key="public_key"config.secret_key="secret_key"config.auth_type="Uploadcare"config.use_subdomains=falseendOr build configuration objects directly:
base_config=Uploadcare::Configuration.new(public_key: "public_key",secret_key: "secret_key")client=Uploadcare::Client.new(config: base_config)Configuration objects are copyable:
account_a=Uploadcare::Client.new(config: base_config.with(public_key: "pk-a",secret_key: "sk-a"))account_b=Uploadcare::Client.new(config: base_config.with(public_key: "pk-b",secret_key: "sk-b"))Common configuration options:
public_keysecret_keyauth_typemultipart_size_thresholdmultipart_chunk_sizeupload_threadsupload_timeoutmax_upload_retriessign_uploadsupload_signature_lifetimeuse_subdomainscdn_base_postfixdefault_cdn_base
CDN helpers:
Uploadcare.configuredo |config|
config.use_subdomains=trueconfig.cdn_base_postfix="https://ucarecd.net/"config.default_cdn_base="https://ucarecdn.com/"endUploadcare.configuration.custom_cnameUploadcare.configuration.cdn_baseThe gem is designed to support multiple Uploadcare projects in the same process:
primary=Uploadcare::Client.new(public_key: "pk-1",secret_key: "sk-1")secondary=Uploadcare::Client.new(public_key: "pk-2",secret_key: "sk-2")primary_file=primary.files.find(uuid: "uuid-1")secondary_file=secondary.files.find(uuid: "uuid-2")You can also derive temporary variants from an existing client:
admin_client=primary.with(secret_key: "different-secret")Resource objects retain their client context, so subsequent instance operations stay bound to the correct account.
client.uploads.upload accepts:
- an IO or file object
- an array of IO or file objects
- an HTTP or HTTPS URL string
file=File.open("photo.jpg","rb")do |io|
client.uploads.upload(io,store: true)endremote_file=client.uploads.upload("https://example.com/image.jpg",store: true)file=File.open("photo.jpg","rb")do |io|
client.files.upload(io,store: true,metadata: {subsystem: "avatars"})endfiles=[File.open("photo-1.jpg","rb"),File.open("photo-2.jpg","rb")]uploaded=client.uploads.upload(files,store: true)files.each(&:close)Synchronous:
file=client.files.upload_from_url("https://example.com/image.jpg",store: true)Async:
job=client.uploads.upload_from_url(url: "https://example.com/image.jpg",async: true,store: true)status=client.uploads.upload_from_url_status(token: job.fetch("token"))When async mode is enabled, the convenience layer returns the raw status token hash because the file does not exist yet.
Polling options for synchronous URL uploads:
poll_interval(default:1) initial status polling interval in secondspoll_max_interval(default:10) maximum polling interval in secondspoll_timeout(default:300) maximum total polling time in seconds
File.open("large-video.mp4","rb")do |io|
file=client.uploads.multipart_upload(file: io,store: true,threads: 4)do |progress|
uploaded=progress[:uploaded]total=progress[:total]puts"#{uploaded}/#{total}"endputsfile.uuidendYou can enable signed uploads globally:
client=Uploadcare::Client.new(public_key: "public",secret_key: "secret",sign_uploads: true)Or pass explicit signature data per request:
File.open("photo.jpg","rb")do |io|
client.files.upload(io,signature: "signature",expire: 1_900_000_000)endCommon upload options:
store: true | false | "auto"metadata: { key: value }signature: "..."expire: unix_timestampasync: truefor URL uploadsthreads:andpart_size:for multipart uploads
If you prefer the older top-level style, the same flows can still be written through the global client:
Uploadcare.configuredo |config|
config.public_key=ENV.fetch("UPLOADCARE_PUBLIC_KEY")config.secret_key=ENV.fetch("UPLOADCARE_SECRET_KEY")endfile=File.open("photo.jpg","rb")do |io|
Uploadcare.files.upload(io,store: true)endfile=client.files.find(uuid: "file-uuid")files=client.files.list(limit: 100)files.each{ |file| putsfile.uuid}List responses are Uploadcare::Collections::Paginated:
files.next_pagefiles.previous_pagefiles.allFilters and API parameters can still be passed through:
files=client.files.list(stored: true,removed: false,limit: 100)file.storefile.deletefile.reloadfile.reload(params: {include: "appdata"})result=client.files.batch_store(uuids: ["uuid-1","uuid-2"])putsresult.statusputsresult.result.map(&:uuid)putsresult.problemsThe same shape applies to client.files.batch_delete.
copied=client.files.copy_to_local(source: file.uuid,options: {store: true})remote_url=client.files.copy_to_remote(source: file.uuid,target: "custom_storage")Instance-level variants are also available:
copied=file.copy_to_local(options: {store: true})remote_url=file.copy_to_remote(target: "custom_storage")Create a group:
group=client.groups.create(uuids: ["uuid-1","uuid-2"])Find and list groups:
group=client.groups.find(group_id: "group-uuid~2")groups=client.groups.list(limit: 50)Delete a group:
group.deleteUseful group helpers:
group.cdn_urlgroup.file_cdn_urlsFetch the current project:
project=client.project.currentputsproject.nameputsproject.pub_keyputsproject.collaboratorsclient.file_metadata.update(uuid: file.uuid,key: "category",value: "avatar")client.file_metadata.show(uuid: file.uuid,key: "category")client.file_metadata.index(uuid: file.uuid)client.file_metadata.delete(uuid: file.uuid,key: "category")Uploadcare::FileMetadata is also available as a resource if you need to hold metadata state locally.
webhook=client.webhooks.create(target_url: "https://example.com/uploadcare",event: "file.uploaded",is_active: true)client.webhooks.listclient.webhooks.update(id: webhook.id,is_active: false)client.webhooks.delete(target_url: webhook.target_url)execution=client.addons.aws_rekognition_detect_labels(uuid: file.uuid)client.addons.aws_rekognition_detect_labels_status(request_id: execution.request_id)scan=client.addons.uc_clamav_virus_scan(uuid: file.uuid)client.addons.uc_clamav_virus_scan_status(request_id: scan.request_id)background=client.addons.remove_bg(uuid: file.uuid)client.addons.remove_bg_status(request_id: background.request_id)These methods return Uploadcare::AddonExecution resources.
Document conversions:
info=client.conversions.documents.info(uuid: file.uuid)job=client.conversions.documents.convert(uuid: file.uuid,format: :pdf)status=client.conversions.documents.status(token: job.fetch("result").first.fetch("token"))Video conversions:
job=client.conversions.videos.convert(uuid: file.uuid,format: :webm,quality: :normal)status=client.conversions.videos.status(token: job.result.first.fetch("token"))Document conversion convert returns the API response hash.
Video conversion convert returns a Uploadcare::VideoConversion resource.
The gem includes signed URL generators for delivery workflows.
generator=Uploadcare::SignedUrlGenerators::AkamaiGenerator.new(cdn_host: "example.com",secret_key: "your_hex_encoded_akamai_secret")signed_url=generator.generate_url("a7d5645e-5cd7-4046-819f-a6a2933bafe3")Custom ACL and wildcard examples:
generator.generate_url("a7d5645e-5cd7-4046-819f-a6a2933bafe3","/*")generator.generate_url("a7d5645e-5cd7-4046-819f-a6a2933bafe3",wildcard: true)The convenience layer raises exceptions:
Uploadcare::Exception::RequestErrorUploadcare::Exception::InvalidRequestErrorUploadcare::Exception::NotFoundErrorUploadcare::Exception::UploadErrorUploadcare::Exception::MultipartUploadErrorUploadcare::Exception::UploadTimeoutErrorUploadcare::Exception::ThrottleError
Example:
beginclient.files.find(uuid: "missing")rescueUploadcare::Exception::NotFoundError=>ewarne.messageendThe raw API layer returns Uploadcare::Result:
result=client.api.rest.files.info(uuid: "file-uuid")ifresult.success?putsresult.successelsewarnresult.error_messageendMost API calls accept request_options: and pass them to the HTTP layer.
Example:
client.files.find(uuid: "file-uuid",request_options: {timeout: 10})Use this when you need per-request timeout control without changing the client’s default configuration.
The gem exposes full endpoint-level access through client.api.
REST API:
client.api.rest.files.list(params: {limit: 10})client.api.rest.files.info(uuid: "file-uuid")client.api.rest.project.showclient.api.rest.webhooks.listUpload API:
File.open("photo.jpg","rb")do |io|
client.api.upload.files.direct(file: io,store: true)endclient.api.upload.files.from_url(source_url: "https://example.com/image.jpg",async: true)client.api.upload.groups.create(files: ["uuid-1","uuid-2"])Use this layer when you want exact control over the documented endpoints or when you are wrapping the gem from another library.
The raw layer is part of the public surface, but it is intentionally less promoted than client.files, client.groups, and the other convenience accessors.
- api_examples/README.md: one canonical script per documented REST and Upload API endpoint
- examples/README.md: workflow-oriented demos built on the public client API
Run examples with project-managed Ruby:
mise exec -- ruby api_examples/rest_api/get_project.rb
mise exec -- ruby examples/simple_upload.rb spec/fixtures/kitten.jpegSee: