NewInstance Documentation
View as Markdown

Source Maps & Symbols

Build/CI-time upload of symbolication inputs: R8/ProGuard mappings, source maps, Dart symbols, Apple dSYM archives and Android ELF objects. All uploads use a presign → PUT-to-storage → complete flow, so the file never transits this API and is not bound by request-size limits. Requires the symbols:upload scope; most integrators should use @newinstance/bugwatch-cli, which performs all three steps.

Artifact upload · step 1 – presign

POST/api/v1/bugwatch/artifacts/presign

Requests a presigned URL for a text symbolication artifact. This is step 1 of 2.

Scope: symbols:upload · Auth: project secret key (keyId:secret)

artifactTypeFilePlatform
r8 / proguardmapping.txtandroid
sourcemap.mapios · react-native · android
dart-symbols--split-debug-info outputflutter
dsymApple dSYM referenced as an artifactios

The file never passes through this API. You presign, PUT the bytes straight to storage, then confirm. That is why uploads are not bound by request-size limits; the previous raw-body routes were rejected by the edge proxy for any real symbol file.

1. POST  …/presign                       → { uploadId, uploadUrl, expiresAt }
2. PUT   <uploadUrl>                      → the raw bytes, streamed to storage
3. POST  …/uploads/{uploadId}/complete    → verified, then queued

The API key goes on steps 1 and 3 only, never to the storage host, which is authorized by the presigned URL's own signature.

Uploads are idempotent per (release, platform, artifactType): completing a new upload replaces the previous artifact and deletes the superseded file.

The release you declare must match the release your SDK reports at runtime, or the artifact exists but nothing matches it and stacks stay unreadable.

Most integrators should use the CLI, which performs all three steps, streams the file (flat memory regardless of size) and retries transient failures:

# Binary debug-symbol archives - Apple dSYM, Android native .so
npx @newinstance/bugwatch-cli symbols upload MyApp.xcarchive \
  --release "1.4.2" --build-number "318"

# Text artifacts - R8/ProGuard mapping, source map, Dart symbols
npx @newinstance/bugwatch-cli artifacts upload mapping.txt \
  --release "1.4.2" --platform android --type r8

The two commands are not interchangeable: symbols upload accepts binary archives only and validates magic bytes, so a mapping.txt or .map is rejected.

Authorization

x-api-keyAPI key · headerrequired

Request body

application/json
{
  "release": "1.0.0",
  "platform": "android",
  "artifactType": "r8",
  "size": 128394,
  "sha256": "3b8f2a91c0de4b7a8f13d6c25e09a4b1f87c30d2416e5a9b8c7d0e1f2a3b4c1d",
  "originalName": "mapping.txt"
}

Responses

201Presigned
400Validation error
401Invalid or missing API key
403Missing symbols:upload
curl -X POST 'https://api.newinstance.cloud/api/v1/bugwatch/artifacts/presign' \
  -H 'x-api-key: YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  --data-raw '{
  "release": "1.0.0",
  "platform": "android",
  "artifactType": "r8",
  "size": 128394,
  "sha256": "3b8f2a91c0de4b7a8f13d6c25e09a4b1f87c30d2416e5a9b8c7d0e1f2a3b4c1d",
  "originalName": "mapping.txt"
}'
Response
{
  "uploadId": "665f1f77bcf86cd799439021",
  "uploadUrl": "https://storage.newinstance.cloud/presigned/665f1f77bcf86cd799439021?sig=…",
  "expiresAt": "2026-08-05T12:15:00.000Z"
}

Artifact upload · step 2 – complete

POST/api/v1/bugwatch/artifacts/uploads/{uploadId}/complete

Confirms the artifact landed in storage and makes it the active artifact for its (release, platform, artifactType). This is step 2 of 2.

Scope: symbols:upload

uploadId in the path is the id returned by step 1, the presign request.

What is verified

  • complete confirms the object actually landed in storage and that its size matches what was declared at presign.
  • The pending row is looked up scoped to the calling project, so one project can never finalize another's upload (a miss returns 404).
  • Only an AWAITING_UPLOAD row can be completed, so a completion cannot be replayed to re-queue processing. Completing it again answers 200 with alreadyCompleted: true.
  • For debug symbols the worker re-hashes the real bytes before indexing and rejects a mismatch (CHECKSUM_MISMATCH). A declared checksum is never trusted on its own.

Authorization

x-api-keyAPI key · headerrequired

Parameters

uploadIdpath · stringrequireddefault:

Responses

200Upload already completed
201Stored and active
400Size mismatch
401Invalid or missing API key
404Upload not found
409File never uploaded
curl -X POST 'https://api.newinstance.cloud/api/v1/bugwatch/artifacts/uploads/{uploadId}/complete' \
  -H 'x-api-key: YOUR_API_KEY'
Response
{
  "fileId": "f_9a2b1c3d4e5f",
  "sha256": "3b8f2a91c0de4b7a8f13d6c25e09a4b1f87c30d2416e5a9b8c7d0e1f2a3b4c1d",
  "alreadyCompleted": true
}

Debug symbols · step 1 – presign

POST/api/v1/bugwatch/debug-symbols/presign

Requests a presigned URL for a binary debug-symbol archive. This is step 1 of 2.

Scope: symbols:upload · Auth: project secret key (keyId:secret)

PlatformAccepted
ios · macos · tvos · watchos · visionos · catalyst.zip of .dSYM bundles, .xcarchive dSYMs, or a raw Mach-O
androidRaw ELF .so / .debug

The file never passes through this API. You presign, PUT the bytes straight to storage, then confirm. That is why uploads are not bound by request-size limits; the previous raw-body routes were rejected by the edge proxy for any real symbol file.

1. POST  …/presign                       → { uploadId, uploadUrl, expiresAt }
2. PUT   <uploadUrl>                      → the raw bytes, streamed to storage
3. POST  …/uploads/{uploadId}/complete    → verified, then queued

The API key goes on steps 1 and 3 only, never to the storage host, which is authorized by the presigned URL's own signature.

Matching is by debug UUID / build-id, the identifier embedded in the binary, not by release name. That is why an upload from any build machine resolves crashes from any device running that exact binary, and why release here is metadata for search rather than the match key. (Source maps and mappings are the opposite: those match on release + platform.)

Declaring a sha256 that already exists for this project short-circuits as a duplicate and returns no uploadUrl, so the transfer is skipped entirely.

Most integrators should use the CLI, which performs all three steps, streams the file (flat memory regardless of size) and retries transient failures:

# Binary debug-symbol archives - Apple dSYM, Android native .so
npx @newinstance/bugwatch-cli symbols upload MyApp.xcarchive \
  --release "1.4.2" --build-number "318"

# Text artifacts - R8/ProGuard mapping, source map, Dart symbols
npx @newinstance/bugwatch-cli artifacts upload mapping.txt \
  --release "1.4.2" --platform android --type r8

The two commands are not interchangeable: symbols upload accepts binary archives only and validates magic bytes, so a mapping.txt or .map is rejected.

Authorization

x-api-keyAPI key · headerrequired

Request body

application/json
{
  "platform": "ios",
  "release": "1.0.0",
  "buildNumber": "318",
  "size": 48210944,
  "sha256": "9c1e5b7a3f28d4c6b0a1e9f2d5c8b7a64310f2e7d9c1b5a8e3f60412789bcf02",
  "originalName": "MyApp.app.dSYM.zip"
}

Responses

200Archive already uploaded, transfer skipped
201Presigned
400Validation error
401Invalid or missing API key
403Missing symbols:upload
curl -X POST 'https://api.newinstance.cloud/api/v1/bugwatch/debug-symbols/presign' \
  -H 'x-api-key: YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  --data-raw '{
  "platform": "ios",
  "release": "1.0.0",
  "buildNumber": "318",
  "size": 48210944,
  "sha256": "9c1e5b7a3f28d4c6b0a1e9f2d5c8b7a64310f2e7d9c1b5a8e3f60412789bcf02",
  "originalName": "MyApp.app.dSYM.zip"
}'
Response
{
  "uploadId": "665f1f77bcf86cd799439011",
  "status": "AVAILABLE",
  "duplicate": true
}

Debug symbols · step 2 – complete

POST/api/v1/bugwatch/debug-symbols/uploads/{uploadId}/complete

Confirms the archive landed in storage and queues it for indexing. This is step 2 of 2.

Scope: symbols:upload

uploadId in the path is the id returned by step 1, the presign request. After this call, poll Get upload status for indexing progress.

What is verified

  • complete confirms the object actually landed in storage and that its size matches what was declared at presign.
  • The pending row is looked up scoped to the calling project, so one project can never finalize another's upload (a miss returns 404).
  • Only an AWAITING_UPLOAD row can be completed, so a completion cannot be replayed to re-queue processing. Completing it again answers 200 with alreadyCompleted: true.
  • For debug symbols the worker re-hashes the real bytes before indexing and rejects a mismatch (CHECKSUM_MISMATCH). A declared checksum is never trusted on its own.

Archive-type validation happens in the worker, not here, because this API never sees the bytes. An archive that is not a zip / Mach-O / ELF lands as INVALID with UNRECOGNIZED_ARCHIVE; an ELF declared under an Apple platform fails with ARCHIVE_PLATFORM_MISMATCH.

Authorization

x-api-keyAPI key · headerrequired

Parameters

uploadIdpath · stringrequireddefault:

Responses

200Queued for indexing
400Size mismatch
401Invalid or missing API key
404Upload not found
409File never uploaded
curl -X POST 'https://api.newinstance.cloud/api/v1/bugwatch/debug-symbols/uploads/{uploadId}/complete' \
  -H 'x-api-key: YOUR_API_KEY'
Response
{
  "uploadId": "665f1f77bcf86cd799439031",
  "status": "QUEUED"
}

List debug symbol uploads

GET/api/v1/bugwatch/debug-symbols/uploads

Lists this project's recent debug symbol uploads, newest first.

Scope: symbols:read

Authorization

x-api-keyAPI key · headerrequired

Parameters

limitquery · stringdefault:

Optional. Number of uploads to return, 1 to 200. Defaults to 50.

Responses

200Uploads list
401Invalid or missing API key
403Missing symbols:read
curl -X GET 'https://api.newinstance.cloud/api/v1/bugwatch/debug-symbols/uploads?limit=20' \
  -H 'x-api-key: YOUR_API_KEY'
Response
{
  "uploads": [
    {
      "uploadId": "507f1f77bcf86cd799439011",
      "status": "AVAILABLE",
      "platform": "ios",
      "release": "2.1.0",
      "buildNumber": "1042",
      "originalFilename": "MyApp.app.dSYM.zip",
      "uploadedSize": 4823012,
      "discoveredUuids": 3,
      "validObjects": 3,
      "invalidObjects": 0,
      "createdAt": "2026-06-26T10:00:00.000Z",
      "completedAt": "2026-06-26T10:00:15.000Z"
    }
  ]
}

Get upload status

GET/api/v1/bugwatch/debug-symbols/uploads/{uploadId}

Returns the processing status and indexing summary of one debug symbol upload.

Scope: symbols:read

uploadId in the path comes from the presign response.

Status flow: QUEUED, then EXTRACTING, then one of AVAILABLE, PARTIALLY_AVAILABLE (some objects were invalid), INVALID or FAILED.

Poll this until status is AVAILABLE or PARTIALLY_AVAILABLE before relying on symbolication.

Authorization

x-api-keyAPI key · headerrequired

Parameters

uploadIdpath · stringrequireddefault:

Responses

200Upload detail
400Upload id is not valid
401Invalid or missing API key
404Upload not found
curl -X GET 'https://api.newinstance.cloud/api/v1/bugwatch/debug-symbols/uploads/{uploadId}' \
  -H 'x-api-key: YOUR_API_KEY'
Response
{
  "uploadId": "507f1f77bcf86cd799439011",
  "status": "AVAILABLE",
  "platform": "ios",
  "release": "2.1.0",
  "buildNumber": "1042",
  "discoveredDsyms": 2,
  "discoveredUuids": 3,
  "validObjects": 3,
  "invalidObjects": 0,
  "failureCode": null,
  "failureMessage": null,
  "createdAt": "2026-06-26T10:00:00.000Z",
  "completedAt": "2026-06-26T10:00:15.000Z"
}

Reprocess – re-symbolicate waiting crashes

POST/api/v1/bugwatch/debug-symbols/uploads/{uploadId}/reprocess

Re-symbolicates crashes that arrived before this upload's symbols did.

Scope: symbols:reprocess

uploadId in the path is the debug symbol upload the waiting crashes need. Crashes still waiting for its symbols, or only partly symbolicated, are queued again and processed with them. Send an empty body.

Authorization

x-api-keyAPI key · headerrequired

Parameters

uploadIdpath · stringrequireddefault:

Responses

200Crashes queued for re-symbolication
400Upload id is not valid
401Invalid or missing API key
403Missing symbols:reprocess
404Upload not found
curl -X POST 'https://api.newinstance.cloud/api/v1/bugwatch/debug-symbols/uploads/{uploadId}/reprocess' \
  -H 'x-api-key: YOUR_API_KEY'
Response
{
  "requeued": 12
}