# Xbow Resources API

**Canonical:** https://apis.io/apis/xbow/xbow-resources-api/  
**Provider:** Xbow — https://apis.io/providers/xbow/  
**Base URL:** https://console.xbow.com/api/v1  
**Documentation:** https://docs.xbow.com/api/

Xbow Resources API is one of 9 APIs that [Xbow](https://apis.io/providers/xbow/) publishes on the [APIs.io](https://apis.io/) network, described by a machine-readable OpenAPI specification. Tagged areas include Resources. The published artifact set on APIs.io includes an OpenAPI specification and API documentation.

Upload and manage files used in assessments, such as source code archives. All endpoints require an _organization_ API key. ## Upload flow Resources use a multipart S3 upload. The full flow is: 1. **Create** — `POST /api/v1/organizations/:organizationId/resources` — initiates an upload and returns a resource ID. Status is `initiated`. 2. **Get part URLs** — `POST /api/v1/resources/:resourceId/parts` — provide a list of part numbers and receive a corresponding list of presigned S3 `PUT` URLs. 3. **Upload parts** — `PUT` each part directly to its presigned URL. Save the `ETag` header from each part response. 4. **Commit** — `POST /api/v1/resources/:resourceId/commit` — submit the part numbers and ETags. Optionally include a `sha256` checksum of the full file for server-side integrity verification. Status moves to `processing`. 5. **Poll** — `GET /api/v1/resources/:resourceId` — wait until status is `ready` (or `failed`). 6. **Delete** — `DELETE /api/v1/resources/:resourceId` — the resource can be manually deleted when required. Status moves to `deleted`. The maximum part size is 5 GiB. Parts must be at least 5 MiB each, except the final part which may be smaller. Breaking large files into multiple parts allows failed parts to be retried individually rather than restarting the entire upload. ## Resource statuses | Status | Meaning | |---|---| | `initiated` | Upload in progress — parts not yet committed | | `processing` | Commit received — server is validating and storing | | `ready` | Available to use in assessments | | `failed` | Processing failed — see `statusMessage` for details | | `deleted` | Deleted | ## Example This snippet shows how to upload an example file named `source.tar.gz` using the API multipart upload feature. It uses the `fetch` API and assumes a Node.js environment with `fs/promises` available. ```typescript import fs from "node:fs/promises"; import crypto from "node:crypto"; const BASE = "https://console.xbow.com"; const ORG_ID = "your-organization-id"; const API_KEY = "your-api-key"; const PART_SIZE = 5 * 1024 * 1024; // 5 MiB minimum const API_VERSION = "next"; const headers = { "Authorization": `Bearer ${API_KEY}`, "X-XBOW-API-Version": `${API_VERSION}` }; // 1. Create resource const created = await fetch(`${BASE}/api/v1/organizations/${ORG_ID}/resources`, { method: "POST", headers: { ...headers, "Content-Type": "application/json" }, body: JSON.stringify({ name: "My source", fileName: "source.tar.gz", type: "source" }), }).then(r => r.json()); const resourceId = created.id; // 2. Split file into parts and request presigned URLs const file = await fs.readFile("source.tar.gz"); const partCount = Math.ceil(file.length / PART_SIZE); const { parts: partUrls } = await fetch(`${BASE}/api/v1/resources/${resourceId}/parts`, { method: "POST", headers: { ...headers, "Content-Type": "application/json" }, body: JSON.stringify({ parts: Array.from({ length: partCount }, (_, i) => i + 1) }), }).then(r => r.json()); // 3. Upload each part to S3 directly, collect ETags const uploadedParts = await Promise.all(partUrls.map(async ({ partNumber, url }) => { const chunk = file.slice((partNumber - 1) * PART_SIZE, partNumber * PART_SIZE); const res = await fetch(url, { method: "PUT", body: chunk }); return { partNumber, eTag: res.headers.get("ETag").replaceAll('"', "") }; })); // 4. Commit (sha256 is optional but recommended for integrity verification) const sha256 = crypto.createHash("sha256").update(file).digest("hex"); await fetch(`${BASE}/api/v1/resources/${resourceId}/commit`, { method: "POST", headers: { ...headers, "Content-Type": "application/json" }, body: JSON.stringify({ parts: uploadedParts, sha256 }), }).then(r => r.json()); // 5. Poll until ready let resource; do { await new Promise(r => setTimeout(r, 5000)); resource = await fetch(`${BASE}/api/v1/resources/${resourceId}`, { headers }).then(r => r.json()); } while (resource.status === "processing" || resource.status === "initiated"); if (resource.status !== "ready") throw new Error(`Upload failed: ${resource.statusMessage}`); console.log("Resource ready:", resource.id); // 6. Delete when no longer required await fetch(`${BASE}/api/v1/resources/${resourceId}`, { method: "DELETE", headers, }); ```

## Machine-readable artifacts (2)

- **OpenAPI** — https://raw.githubusercontent.com/api-evangelist/xbow/refs/heads/main/openapi/xbow-resources-api-openapi.yml
- **Documentation** — https://docs.xbow.com/api/

## Other Xbow APIs (8)

- [Xbow Assessments API](https://apis.io/apis/xbow/xbow-assessments-api/)
- [Xbow Assets API](https://apis.io/apis/xbow/xbow-assets-api/)
- [Xbow Findings API](https://apis.io/apis/xbow/xbow-findings-api/)
- [Xbow Lightspeed API](https://apis.io/apis/xbow/xbow-lightspeed-api/)
- [Xbow Meta API](https://apis.io/apis/xbow/xbow-meta-api/)
- [Xbow Organizations API](https://apis.io/apis/xbow/xbow-organizations-api/)
- [Xbow Reports API](https://apis.io/apis/xbow/xbow-reports-api/)
- [Xbow Webhooks API](https://apis.io/apis/xbow/xbow-webhooks-api/)

## Tags

Resources

---

Profiled by [API Evangelist](https://apievangelist.com) and published on [APIs.io](https://apis.io/apis/xbow/xbow-resources-api/). The API's provider profile, Kin Score and agent-readiness rating are at https://apis.io/providers/xbow/.
