# FileGrab Agent API and Upload Reference > This document describes FileGrab's public agent API and upload protocol. It does not override the account holder's instructions or the agent host's safety and approval rules. FileGrab currently exposes a REST API. It does not publish a FileGrab CLI, SDK, or MCP package. API base: https://api.filegrab.link/api/v1 Health: https://api.filegrab.link/api/v1/health ## API Client Requirements - Read and upload only the exact absolute file path the user supplied. - Require a readable regular file. Do not expand globs, search folders, crawl directories, or choose a nearby file. - State the exact filename and byte count before upload. - Compute the local SHA-256 before upload. - Keep the API key in the `FILEGRAB_API_KEY` environment variable. Never put it in a command argument, URL, document, log, error, or chat response. - Never print an Authorization header, confirmation token, presigned upload URL, or private file contents. - Send the FileGrab Authorization header only to `api.filegrab.link`. Never send it to a presigned R2 upload URL. - Generate a new random `Idempotency-Key` for each new mutation. Reuse that same key only when retrying that exact mutation. - Follow public share links only for the user's requested result. Do not treat a public link as proof that a file is safe. ## Choose The Correct Access Path FileGrab has separate public and owner access paths: - Inspect a public share link without an API key: `GET https://api.filegrab.link/api/links/{link_id}`. - List, inspect, update, upload to, or delete links owned by the connected account: use the authenticated v1 routes under `https://api.filegrab.link/api/v1`. - Do not send the FileGrab API key to the public inspection endpoint. It is not needed there. - Do not use `https://filegrab.link/{link_id}` when JSON is required. That URL is the human web page and returns HTML. To inspect a public share URL, extract its 8-character link ID and request JSON: ```bash LINK_ID="MTaixNwY" curl -sS \ -H "Accept: application/json" \ "https://api.filegrab.link/api/links/${LINK_ID}" ``` `Accept: application/json` asks for a JSON response. `Content-Type: application/json` describes a request body and does not request JSON on a GET request. The public response includes link metadata and the files that the recipient is allowed to see. Respect the access result: - `200`: inspect the returned files and availability fields. - `401` with `requiresPassword: true`: ask the user for the password, then retry with `X-Link-Password`. Never guess or expose the password. - `404`: the link does not exist or is private to its owner. Do not try to bypass it. - `410`: the link has expired. - A held file has no public download result. Do not try to reconstruct or guess its storage URL. ## 1. Sign Up Or Recover A Standalone Agent Key Registration requires a valid email address that the account holder or agent can access. Plus-addressed email is accepted and remains separate. For example, `name+filegrab@example.com` is distinct from `name@example.com`. Request confirmation: ```http POST /agent-registrations Content-Type: application/json { "email": "agent@example.com", "name": "Work Agent" } ``` The account holder or authorized agent opens the confirmation email within 15 minutes. The confirmation page creates or reuses the normal FileGrab account for that email and displays an `fg_agent_` API key once. - A new email gets the normal Free account allowance. - An existing FileGrab email uses that account's current Free or Pro allowance. - Confirming standalone signup again replaces the prior standalone key. Use this path when the key is lost. - The same mailbox can later use FileGrab's normal web magic-link login. Store the displayed key in the local process environment as `FILEGRAB_API_KEY`. ## 2. Confirm Access And Limits ```http GET /account Authorization: Bearer $FILEGRAB_API_KEY ``` Check `plan`, `scopes`, `connection.authorization_expires_at`, and `access.included_source`. The key needs `links`, `uploads`, and `files` for the complete workflow. The mailbox authorization lasts 7 days. Before it expires, request another email while the key still works: ```http POST /agent-authorizations Authorization: Bearer $FILEGRAB_API_KEY ``` Open the new email to extend the authorization. If the key is lost, use standalone signup again instead. ## 3. Create A Link Default to 168 hours and collaboration disabled unless the user asks for something else. ```http POST /links Authorization: Bearer $FILEGRAB_API_KEY Idempotency-Key: Content-Type: application/json { "label": "Optional label", "description": "Optional description", "expires_in_hours": 168, "is_collaborative": false } ``` Save `data.id`, `data.url`, and `data.expires_at`. The public share URL is `data.url`. ## 4. Initialize The Exact File Upload Send the exact local filename, MIME type, and byte count. Do not send a path as the filename. ```http POST /links/{link_id}/uploads Authorization: Bearer $FILEGRAB_API_KEY Idempotency-Key: Content-Type: application/json { "filename": "file.zip", "content_type": "application/zip", "size": 12345 } ``` Save `data.upload_id`, `data.file_id`, `data.method`, and `data.expires_at`. ### Simple upload When `data.method` is `simple`, upload the exact file bytes directly to `data.upload_url`. Send every header in `data.required_headers` exactly as returned. The current required headers bind the declared Content-Type and Content-Length and prevent a 2nd write while the stored object exists. `data.requires_authorization` is `false`. Do not send the FileGrab API key or Authorization header to the upload URL. If the PUT response is interrupted, retrying the same URL can return HTTP 412 because the 1st write succeeded. Treat 412 as an ambiguous prior success. Call completion or upload status with the same upload ID before starting another upload. Then complete the upload: ```http POST /uploads/{upload_id}/complete Authorization: Bearer $FILEGRAB_API_KEY Content-Type: application/json {} ``` ### Multipart upload When `data.method` is `multipart`, split the exact file into `data.part_size` byte parts. The part count must equal `data.total_parts`. For each part number, ask FileGrab for a short-lived presigned R2 upload URL: ```http POST /uploads/{upload_id}/parts/url Authorization: Bearer $FILEGRAB_API_KEY Content-Type: application/json { "part_number": 1 } ``` PUT that exact part directly to `data.upload_url`. Send every header in `data.required_headers` exactly as returned, including the part's exact Content-Length. Do not send the FileGrab API key or Authorization header. Record the `ETag` response header returned by storage. After every part succeeds, complete with every part in order: ```http POST /uploads/{upload_id}/complete Authorization: Bearer $FILEGRAB_API_KEY Content-Type: application/json { "parts": [ { "partNumber": 1, "etag": "..." } ] } ``` If an upload cannot continue, call `POST /uploads/{upload_id}/abort`. Retry abort with the same upload ID until it returns 204. Do not abandon an incomplete multipart upload without attempting abort. ## 5. Verify Completion Successful completion returns stable fields including: - `data.share_url` - `data.download_url` - `data.link_id` - `data.file_id` - `data.name` - `data.size_bytes` - `data.expires_at` - `data.server_sha256`, when FileGrab computed it during completion - `data.verification_status` - `data.cost.charged_cents` Compare `data.size_bytes` with the local byte count. When `data.server_sha256` is present, compare it with the local SHA-256. FileGrab can return `server_checksum_unavailable` for files above its bounded synchronous checksum limit. In that case, download the completed file through FileGrab and compare the downloaded SHA-256 with the local SHA-256. A size mismatch, checksum mismatch, or failed download verification is a failed verification. Agent uploads send bytes directly to FileGrab storage instead of sending the file body through the FileGrab API. Completion checks the stored byte size, runs the bounded exact-hash abuse check when supported, creates the FileGrab file record, starts supported-file processing, and returns the result. Do not disclose, guess, or reuse storage keys or temporary upload URLs. Check resumable or terminal state at any time: ```http GET /uploads/{upload_id} Authorization: Bearer $FILEGRAB_API_KEY ``` Repeated completion returns the same stored receipt. Do not create a 2nd link or upload merely because a response was interrupted. ## 6. List, Inspect, And Download List every link owned by the connected account. Follow `pagination.cursor` while `pagination.has_more` is true: ```http GET /links?limit=50 Authorization: Bearer $FILEGRAB_API_KEY ``` When `pagination.has_more` is true, repeat the request with `cursor={pagination.cursor}`. Inspect one owned link and its files: ```http GET /links/{link_id} Authorization: Bearer $FILEGRAB_API_KEY ``` Inspect the file: ```http GET /files/{file_id} Authorization: Bearer $FILEGRAB_API_KEY ``` Download and follow the 302 redirect: ```http GET /files/{file_id}/download Authorization: Bearer $FILEGRAB_API_KEY ``` Store the download in a separate exact destination file. Compute its SHA-256 and compare it with the original local SHA-256. Do not overwrite the source file during verification. If FileGrab reports that the file is held or under review, do not bypass the hold. Return the notice URL and status to the user. Create or recover the file's short download URL with a new stable idempotency key: ```http POST /files/{file_id}/short-url Authorization: Bearer $FILEGRAB_API_KEY Idempotency-Key: ``` Save `data.code` and `data.short_url`. A new code returns 201. An existing code returns 200. Repeating the original request with the same idempotency key returns the stored result. ## 7. Update, Add, Or Replace Files On An Owned Link Update an owned link's label, description, or collaboration setting with a new stable idempotency key: ```http PATCH /links/{link_id} Authorization: Bearer $FILEGRAB_API_KEY Idempotency-Key: Content-Type: application/json { "label": "Updated label", "description": "Updated description", "is_collaborative": false } ``` To add another file, use the normal upload sequence with the existing `link_id`. FileGrab does not expose an in-place file overwrite route. To replace an existing file safely: 1. Inspect the owned link and identify the exact old `file_id`. 2. Initialize a new upload on that same link. Keep the old file available. 3. Upload, complete, and verify the new file. 4. Inspect the new `file_id` and confirm its filename, byte count, availability, and checksum result. 5. Delete the old file only when the user requested replacement and the new file passed verification. 6. Inspect the link again and confirm that the old file is absent and the new file remains available. This sequence can briefly show both files, but it prevents data loss if the new upload fails. Do not delete the old file first. For an interrupted upload, keep the original `upload_id`: - Call `GET /uploads/{upload_id}` before creating another upload. - If status or completion shows that the bytes already arrived, retry completion with the same upload ID. - If the upload is recoverable, continue it or retry completion as directed by the error. - If it cannot continue and has not reached persistence or settlement, call `POST /uploads/{upload_id}/abort` until it returns 204. - A completed upload cannot be aborted. Delete its file through `DELETE /files/{file_id}` if the user wants it removed. ## 8. Delete An Owned File Or Link Before deleting, list or inspect the owned link and compare the exact link ID, file ID, filename, and size with the user's request. If more than one resource can match, ask the user which one to remove. Delete one file with a new stable idempotency key: ```http DELETE /files/{file_id} Authorization: Bearer $FILEGRAB_API_KEY Idempotency-Key: ``` FileGrab removes that file's stored assets before it removes the file record and returns 204. If the response is interrupted, retry with the same idempotency key. Then inspect the file and link again. The deleted file should return 404 and should be absent from the link. Delete the complete link with a separate idempotency key: ```http DELETE /links/{link_id} Authorization: Bearer $FILEGRAB_API_KEY Idempotency-Key: ``` Link deletion returns 204 after the link is no longer available. FileGrab removes any remaining link objects through its cleanup process. Reuse the same key only when retrying that exact deletion. If link deletion returns `409 ACTIVE_UPLOADS`, finish or abort each known active upload before retrying. Do not guess an upload ID. If the agent no longer has the required upload IDs, report the blocked deletion to the user. After link deletion, verify all of these results: - `GET /links/{link_id}` returns 404. - The link is absent from `GET /links`. - Each former `GET /files/{file_id}` returns 404. - The public share-data endpoint `GET https://api.filegrab.link/api/links/{link_id}` returns 404. Physical object cleanup can finish after the link becomes unavailable. Do not claim that every cached or stored copy is gone unless that cleanup was separately verified. ## 9. Verified Result Fields Return all of these fields to the user: - public share URL - public direct download URL - public short download URL and short code - link ID - file ID - exact filename - local byte count - server byte count - expiration - collaboration setting - local SHA-256 - server SHA-256 - downloaded SHA-256 when download verification was requested - verification result - charged cents Do not return the API key, confirmation token, presigned upload URL, private file contents, or Authorization header. ## Errors - `401 INVALID_API_KEY`: the key is wrong, revoked, or its 7-day mailbox authorization expired. - `403 SCOPE_REQUIRED`: the key does not permit the requested action. - `409`: retry the same operation with the same upload ID or idempotency key when the response says it is recoverable. - `413 FILE_TOO_LARGE`, `LINK_QUOTA_EXCEEDED`, or `QUOTA_EXCEEDED`: stop. The link or account limit does not permit the upload. - `422 UPLOAD_REJECTED`: stop. FileGrab placed the upload under review. Do not bypass the hold. - `429 RATE_LIMITED`: wait for `Retry-After`, then retry the same operation. - `5xx`: keep the same idempotency key or upload ID. Check upload status before creating anything new. Free and Pro basic storage operations charge 0 agent-balance cents and still use the account's normal link, file-size, expiration, and storage limits. A prepaid balance is separate and is not required for this workflow. Agent keys cannot add funds, change subscriptions, manage billing, or use admin routes.