run402-com Jobs API

The Jobs API from run402-com — 4 operation(s) for jobs.

Operations 6

POST /jobs/v1/runs Submit a managed async job #
DELETE /jobs/v1/runs Purge all managed job runs for the project #
GET /jobs/v1/runs/{job_id} Get managed job status/result #
DELETE /jobs/v1/runs/{job_id} Cancel a managed job #
GET /jobs/v1/runs/{job_id}/logs Get managed job runner logs #
GET /jobs/v1/runs/{job_id}/artifacts/{filename} Download a managed job artifact #

Work with this as data

Every API here is available over the APIs.io API and to AI agents over MCP.

MCP server

One button, every client — Claude, Cursor, VS Code and the rest.

https://apis.io/mcp

Tools for apis

7 MCP tools reach this
  • find_apisBrowse and filter every API in the catalog.
  • get_api_artifactsOne API's artifacts, grouped by type.
  • get_openapiThe primary OpenAPI for this API.
  • find_similar_apisAPIs that look like this one.
  • apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.
  • resolveTurn a domain, URL or GitHub org into the provider it belongs to.
  • find_cohortsEvery scored population of providers in the catalog.
All 92 tools →

Call it yourself

curl for this page
This API
curl "https://apis.io/api/v1/apis/run402-com:run402-com-jobs-api"
All apis
curl "https://apis.io/api/v1/apis?limit=25"

Discovery needs no key. Ratings and market analysis are Pro.

Get an API key

Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.

A second provider on the same verified email joins the account you already have.

OpenAPI Specification

run402-com-jobs-api-openapi.yml Raw ↑
openapi: 3.2.0
info:
  title: Run402 Jobs API
  version: 2.0.0
  description: 'Full-stack infrastructure for AI agents. Postgres, REST API, auth, file storage, static site hosting, serverless functions. Tier payments and image generation use the shared payment engine: x402 (USDC on Base), MPP on Tempo (pathUSD), and the draft-pinned MPP Lightning charge profile (sats, Bitcoin mainnet) for authenticated tier purchases and image generation.'
  contact:
    name: Run402
    url: https://run402.com
  guidance: 'Run402 is a pay-per-use backend for AI agents: Postgres databases, static hosting, serverless functions, and image generation. The shared payment engine supports x402 (USDC on Base), MPP on Tempo (pathUSD), and the exact Run402 MPP Lightning charge profile on Bitcoin mainnet (sats).


    ## Quick start

    1. Install the CLI: npm install -g run402@latest

    2. Create an allowance: run402 init

    3. Set the prototype tier (FREE, testnet USDC): run402 tier set prototype

    4. Provision a project: run402 projects provision --name "my-app"

    5. Deploy: run402 deploy --manifest app.json


    ## Payment model

    - Tiers (prototype $0.10 testnet, hobby $5, team $20; hobby and team are 30-day prepaid leases) unlock all platform features.

    - Image generation is $0.03 per call (x402, MPP on Tempo, or MPP Lightning micropayment).

    - Auth-only endpoints (projects, deploys, messages) require SIWX wallet identity but no payment.


    ## Auth

    - x402 endpoints: include a payment header (handled automatically by the CLI or x402 client libraries).

    - Explicit MPP Lightning tier requests require the exact Run402 profile, ordered Accept-Payment preferences, one principal credential, a stable Idempotency-Key, and buyer-side USD/native/fee limits.

    - SIWX endpoints: sign a CAIP-122 message with your wallet.

    - REST API: use the project''s anon_key or service_key as the apikey header.


    ## Client metadata

    - Recent Node SDK/CLI clients may send Run402-Client: surface="cli", version="3.7.14", sdk="3.7.14". It is advisory, bounded, never used for auth/billing/trust, and not browser-CORS-enabled yet.


    ## Docs

    - Full CLI docs: https://run402.com/llms-cli.txt

    - API docs: https://run402.com/llms.txt'
servers:
- url: https://api.run402.com
  description: Production
tags:
- name: Jobs
paths:
  /jobs/v1/runs:
    post:
      summary: Submit a managed async job
      security:
      - bearerAuth: []
      parameters:
      - name: Idempotency-Key
        in: header
        required: true
        schema:
          type: string
          maxLength: 256
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ManagedJobSubmitRequest'
      responses:
        '200':
          description: Idempotency hit
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ManagedJobResponse'
        '202':
          description: Job accepted
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ManagedJobResponse'
        '409':
          description: Idempotency-key conflict
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '429':
          description: Project job quota exceeded
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '503':
          description: Platform job queue full; Retry-After header is set
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      operationId: submitManagedJob
      tags:
      - Jobs
    delete:
      summary: Purge all managed job runs for the project
      security:
      - bearerAuth: []
      responses:
        '200':
          description: Project-scoped job runs purged
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ManagedJobPurgeResponse'
      operationId: purgeManagedJobs
      tags:
      - Jobs
  /jobs/v1/runs/{job_id}:
    get:
      summary: Get managed job status/result
      security:
      - bearerAuth: []
      parameters:
      - name: job_id
        in: path
        required: true
        schema:
          type: string
      responses:
        '200':
          description: Project-scoped job
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ManagedJobResponse'
        '404':
          description: Job not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      operationId: getManagedJob
      tags:
      - Jobs
    delete:
      summary: Cancel a managed job
      security:
      - bearerAuth: []
      parameters:
      - name: job_id
        in: path
        required: true
        schema:
          type: string
      responses:
        '200':
          description: Cancelled job or existing terminal job
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ManagedJobResponse'
        '404':
          description: Job not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      operationId: cancelManagedJob
      tags:
      - Jobs
  /jobs/v1/runs/{job_id}/logs:
    get:
      summary: Get managed job runner logs
      security:
      - bearerAuth: []
      parameters:
      - name: job_id
        in: path
        required: true
        schema:
          type: string
      - name: tail
        in: query
        required: false
        schema:
          type: integer
          minimum: 1
          maximum: 1000
          default: 100
      - name: since
        in: query
        required: false
        schema:
          type: string
          format: date-time
        description: Inclusive ISO-8601 lower bound. Legacy epoch milliseconds are also accepted.
      responses:
        '200':
          description: Chronological runner logs
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ManagedJobLogsResponse'
        '404':
          description: Job not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '503':
          description: Job logs are not configured
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      operationId: getManagedJobLogs
      tags:
      - Jobs
  /jobs/v1/runs/{job_id}/artifacts/{filename}:
    get:
      summary: Download a managed job artifact
      security:
      - bearerAuth: []
      parameters:
      - name: job_id
        in: path
        required: true
        schema:
          type: string
      - name: filename
        in: path
        required: true
        schema:
          type: string
        description: Artifact filename recorded on the completed job (e.g. proof.json, public.json, prove-output.log).
      responses:
        '200':
          description: 'Artifact bytes streamed with the artifact''s content-type (Cache-Control: private, no-store).'
          content:
            application/octet-stream:
              schema:
                type: string
                format: binary
        '404':
          description: Job not found, not completed, or the filename was not recorded for this job
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      operationId: downloadManagedJobArtifact
      tags:
      - Jobs
components:
  schemas:
    ManagedJobLogEntry:
      type: object
      required:
      - timestamp
      - message
      - log_stream_name
      - event_id
      properties:
        timestamp:
          type: string
          format: date-time
        message:
          type: string
        log_stream_name:
          type: string
        event_id:
          type: string
        ingestion_time:
          type: string
          format: date-time
    ErrorEnvelope:
      type: object
      required:
      - error
      - message
      - code
      - category
      - source
      - retryable
      - safe_to_retry
      - mutation_state
      - trace_id
      - details
      - next_actions
      properties:
        error:
          type: string
          description: Short error label; safe to surface in UI. Do not branch on English text — branch on `code` instead.
        message:
          type: string
          description: Preferred human-readable message.
        code:
          $ref: '#/components/schemas/ErrorCode'
        category:
          $ref: '#/components/schemas/ErrorCategory'
        source:
          type: string
          enum:
          - gateway
          - app
          description: Attribution discriminator (#501). `"gateway"` on every gateway-produced boundary envelope — transport / JSON-parse / authentication / rate-limit failures that precede a tenant function (e.g. VALIDATION_FAILED, AUTH_REQUIRED, INVALID_AUTH, RATE_LIMITED). An application or function error carries no `source` (or the app's own value), so a caller distinguishes a run402-boundary error from an app error. The gateway emits only `"gateway"`; `"app"` is reserved for the function runtime. See https://run402.com/errors/#boundary-errors.
        retryable:
          type: boolean
          description: True when retrying later may succeed without changing the request.
        safe_to_retry:
          type: boolean
          description: True when repeating the same request is not expected to duplicate or corrupt a mutation.
        mutation_state:
          $ref: '#/components/schemas/MutationState'
        trace_id:
          type: string
          description: Client-visible trace identifier also included in gateway error logs.
          example: trc_0123456789abcdef0123456789abcdef
        details:
          type: object
          additionalProperties: true
          description: Structured domain-specific context. Always an object. Gateway-originated errors may include details.client_compatibility when bounded Run402-Client metadata shows that a stale or incompatible client likely contributed to the failure.
        next_actions:
          type: array
          items:
            $ref: '#/components/schemas/NextAction'
          description: Advisory next actions. Always an array. Client compatibility guidance uses type upgrade_client; gateway-authored upgrade_client actions are semantic and do not include local/global install commands. During an open platform incident that correlates with this error's code, the array also carries a `poll` action pointing at the project events feed (see `correlated_platform_incident`).
        correlated_platform_incident:
          type:
          - object
          - 'null'
          required:
          - id
          - subsystem
          - status
          properties:
            id:
              type: string
              description: Stable platform-incident id (`inc_…`). Poll the project events feed for its resolution and final per-project impact count.
              example: inc_9b21fa0c7d4e15a3
            subsystem:
              type: string
              description: The degraded platform subsystem the error's code correlates with (e.g. `lambda_concurrency`, `gateway_5xx`, `gateway`).
            status:
              type: string
              enum:
              - ongoing
              - resolved
              description: Incident lifecycle at stamp time — `ongoing` while the correlated alarm is still firing.
          description: Present only when an OPEN platform incident correlates with this error's `code`. The platform STATES the correlation and lets you judge — it does NOT assert your code is fault-free (an application can cause its own throttling). Treat it as a strong signal to poll the feed (a `poll` next_action is appended) rather than immediately debugging your own code. Absent on any error with no correlated open incident.
      additionalProperties: true
      description: Canonical Run402-originated JSON error envelope. Route-specific extras may appear inside `details` or as top-level siblings (e.g. `phase`, `operation_id`, `lifecycle_state`, `correlated_platform_incident`). PostgREST-native errors and user function responses are passthrough boundaries — they are returned verbatim. A configured hard client-compatibility policy may reject before mutation with code CLIENT_VERSION_UNSUPPORTED, category client_compatibility, mutation_state none, safe_to_retry true, and an upgrade_client next action.
    ErrorResponse:
      $ref: '#/components/schemas/ErrorEnvelope'
    ErrorCode:
      type: string
      enum:
      - VALIDATION_FAILED
      - AUTH_REQUIRED
      - INVALID_AUTH
      - FORBIDDEN
      - TABLE_NOT_EXPOSED
      - TABLE_NOT_LIVE
      - LIVE_CONNECTION_LIMIT
      - PROJECT_NOT_READY
      - METHOD_NOT_ALLOWED
      - ADMIN_REQUIRED
      - PAYMENT_REQUIRED
      - payment_insufficient_funds
      - RATE_LIMITED
      - CLIENT_VERSION_UNSUPPORTED
      - QUOTA_EXCEEDED
      - PROJECT_NOT_FOUND
      - RESOURCE_NOT_FOUND
      - PROJECT_PAST_DUE
      - PROJECT_FROZEN
      - PROJECT_DORMANT
      - MIGRATE_GATE_ACTIVE
      - PLAN_NOT_FOUND
      - OPERATION_NOT_FOUND
      - INVALID_STATE
      - NOT_RESUMABLE
      - MIGRATION_FAILED
      - MIGRATION_CHECKSUM_MISMATCH
      - AMBIGUOUS_MAILBOX
      - DEFAULT_MAILBOX_REQUIRED
      - DEFAULT_MAILBOX_INVALID
      - INBOUND_DOMAIN_ALREADY_ENABLED
      - AMBIGUOUS_INBOUND_DOMAIN
      - AMBIGUOUS_RECIPIENT
      - AMBIGUOUS_EXTERNAL_SELECTION
      - STORAGE_UNAVAILABLE
      - UPSTREAM_UNAVAILABLE
      - INTERNAL_ERROR
      - PAYOUT_WALLET_REQUIRED
      - PAYOUT_WALLET_AMBIGUOUS
      - PAYOUT_WALLET_NOT_LINKED
      - RECIPIENT_PAYOUT_WALLET_REQUIRED
      - PAYOUT_WALLET_UNRESOLVED
      - PAYMENT_PROOF_MISMATCH
      - LIGHTNING_RECEIVER_REQUIRED
      - LIGHTNING_RECEIVER_UNAVAILABLE
      - LIGHTNING_RECEIVER_PROBE_FAILED
      - LIGHTNING_RECEIVER_NOT_FOUND
      - RECIPIENT_LIGHTNING_RECEIVER_REQUIRED
      description: Stable Run402 error code. Most gateway-owned codes are uppercase snake-case; x402-compatible payment rail codes may be lowercase. Endpoints may emit additional stable codes as new surfaces are added; branch on this field before reading error/message text.
    MutationState:
      type: string
      enum:
      - none
      - not_started
      - committed
      - rolled_back
      - partial
      - unknown
      description: Best-known mutation state for the failed request.
    ManagedJobResponse:
      type: object
      required:
      - job_id
      - job_type
      - status
      - created_at
      properties:
        job_id:
          type: string
          example: job_abc123
        job_type:
          type: string
        status:
          type: string
          enum:
          - queued
          - running
          - completed
          - failed
          - cancelled
        created_at:
          type: string
          format: date-time
        started_at:
          type: string
          format: date-time
        completed_at:
          type: string
          format: date-time
        artifacts:
          type: object
          additionalProperties:
            type: object
            properties:
              url:
                type: string
                description: 'Fetchable HTTPS download URL: GET /jobs/v1/runs/{job_id}/artifacts/{filename} (bearerAuth).'
              content_type:
                type: string
              sha256:
                type: string
              size_bytes:
                type: integer
            required:
            - url
            - content_type
          description: Per-artifact download references for a completed job, keyed by filename. sha256/size_bytes are omitted for legacy jobs created before per-artifact integrity capture.
        metadata:
          type: object
          additionalProperties: true
          properties:
            wall_seconds:
              type: integer
            cost_usd_micros:
              type: integer
            raw_cost_usd_micros:
              type: integer
            absorbed_overage_usd_micros:
              type: integer
            image_digest:
              type: string
            spot_rate_usd_hr_micros:
              type: integer
            on_demand_rate_usd_hr_micros:
              type: integer
            instance_type:
              type: string
            az:
              type: string
            peak_rss_gb:
              type: number
            interrupt_count:
              type: integer
            attempt_count:
              type: integer
            billing_status:
              type: string
        error:
          type: object
          required:
          - code
          - message
          properties:
            code:
              type: string
            message:
              type: string
    ManagedJobLogsResponse:
      type: object
      required:
      - logs
      properties:
        logs:
          type: array
          items:
            $ref: '#/components/schemas/ManagedJobLogEntry'
    ErrorCategory:
      type: string
      enum:
      - validation
      - auth
      - billing
      - quota
      - rate_limit
      - lifecycle
      - not_found
      - conflict
      - client_compatibility
      - deploy
      - storage
      - upstream
      - internal
      description: Stable routing category for agent error handling.
    ManagedJobPurgeResponse:
      type: object
      required:
      - deleted_jobs
      - cancelled_active_jobs
      - terminated_instances
      properties:
        deleted_jobs:
          type: integer
          minimum: 0
        cancelled_active_jobs:
          type: integer
          minimum: 0
          description: Queued/running jobs included in the purge.
        terminated_instances:
          type: integer
          minimum: 0
          description: Known EC2 runner instances terminated before deleting records.
    ManagedJobSubmitRequest:
      type: object
      required:
      - job_type
      - input
      - max_cost_usd_micros
      additionalProperties: false
      properties:
        job_type:
          type: string
          description: Whitelisted managed job type configured by run402.
        input:
          type: object
          required:
          - input_json
          additionalProperties: false
          properties:
            input_json:
              type: object
              additionalProperties: true
        max_cost_usd_micros:
          type: integer
          minimum: 0
          description: Hard customer charge ceiling in micro-USD.
        callback_url:
          type: string
          format: uri
          maxLength: 2048
          description: Optional absolute https URL pushed once when the job reaches a terminal state (completed/failed/cancelled), so you need not poll GET /jobs/v1/runs/{job_id}. http and malformed URLs are rejected (400 invalid_job_request, code INVALID_CALLBACK_URL). Delivery is durable (at-least-once, retried, dead-lettered) and unsigned; the body is the canonical webhook envelope { id, type, created_at, schema_version, idempotency_key, payload } where type is one of job_completed/job_failed/job_cancelled and payload is { job_id, status, artifacts?, error? }. The Run402-Webhook-Id header equals the idempotency_key (<job_id>:terminal) — dedupe on it and re-fetch authoritative state via GET before acting; the callback is a trigger, not the source of truth. Submit-only; never returned on read.
    NextAction:
      type: object
      required:
      - type
      properties:
        type:
          type: string
          description: 'Advisory machine-readable action type such as retry, authenticate, submit_payment, fund_wallet, renew_tier, check_usage, resume_deploy, edit_request, edit_migration, contact_support, upgrade_client, poll (poll the project events feed — appended when the envelope carries a correlated_platform_incident), or hand_to_member (on a commit/promote response that just activated a public site: show the human urls.site and urls.console, relay Run402''s offer to promote the build on @run402com, and ask yes or no — see `credited_as` below). create_app_repo (APP_REPO_NOT_FOUND: POST /projects/v1/:project_id/app-repos { repo_name } before reading, committing or pushing a named repo).'
        method:
          type: string
          example: POST
        path:
          type: string
          example: /tiers/v1/hobby
        auth:
          type: string
          example: x402
        why:
          type: string
        credited_as:
          type:
          - string
          - 'null'
          description: '`hand_to_member` only. The caller''s own live presence name in the project''s default room, else that room''s most recently active live presence, else `null` — in which case `why` tells the agent that joining the room with a name (`run402 rooms join --name ...`) is how the promotion credits it.'
        body:
          type: object
          description: '`hand_to_member` only. A ready-to-send `POST /feedback/v1` template: `{ project_id, message: "promote: yes", handle? }`.'
      additionalProperties: true
  securitySchemes:
    operatorSession:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: 'The sign-in session bearer (control_plane_session): principal-bound, graded by provenance (grade: browser | loopback | device — device is read-only), 30-min access TTL, 12h absolute cap, jti-revocable.'
    apikey:
      type: apiKey
      in: header
      name: apikey
      description: Project JWT in the apikey header. Most client-facing routes accept the project anon_key; privileged project operations require a service_key or project_admin JWT.
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: 'User access_token from /auth/v1/token. Pass as Authorization: Bearer <token>.'
    serviceKey:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: 'Project service_key (JWT with service_role). Returned when you provision a project. Pass as Authorization: Bearer <service_key>.'
    adminKey:
      type: apiKey
      in: header
      name: x-admin-key
      description: Server admin key. Required for admin operations.
    x402:
      type: apiKey
      in: header
      name: X-PAYMENT
      description: x402 payment header. The client library (e.g. @anthropic-ai/sdk x402 facilitator) handles this automatically. Payment is in USDC on Base (mainnet eip155:8453 or testnet eip155:84532).
    mppPayment:
      type: apiKey
      in: header
      name: Authorization
      description: MPP Payment credential for the exact retained Lightning charge challenge. The credential is sent only after the fixed invoice settles; portable receipts contain the payment hash, never the preimage.
    walletAuth:
      type: apiKey
      in: header
      name: SIGN-IN-WITH-X
      description: SIWX (Sign-In-With-X, CAIP-122 / EIP-4361) wallet authentication. Send a single SIGN-IN-WITH-X header containing a base64-encoded JSON payload with a signed CAIP-122 message (domain binding, temporal validation, cryptographic signature). Supports both EVM (eip155:*) and Solana wallets. Most wallet-auth endpoints require an active tier; endpoints that only require identity say so in their description. See https://docs.x402.org/extensions/sign-in-with-x.
    ciSessionAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: 'CI session JWT from POST /ci/v1/token-exchange. HS256, signed with CI_SESSION_SECRET (server-controlled). Carries `token_use:"ci_session"`, 15-min TTL bounded by binding expiry. Accepted on the CI-callable deploy routes: all `/content/v1/plans*` writes, all `/apply/v1/plans*` writes, GET `/apply/v1/operations/{operation_id}` + `/events` + `/edge-coherence`, POST `/apply/v1/operations/{operation_id}/resume`. ALSO the own-project error-read surface GET `/projects/v1/{project_id}/errors` + `/{fingerprint_id}` (read-only; the deploy→watch promote gate, keyless). The binding is created via SIWE at POST /ci/v1/bindings. See "OIDC federation for CI/CD" in llms-full.txt.'
    browserSession:
      type: apiKey
      in: cookie
      name: __Host-Http-r402_session
      description: Hosted browser-session cookie minted by the hosted-auth ceremony on <project>.run402.app / a verified custom domain. Backs the headless <AccountSecurity> component and the documented-advanced non-Astro /auth/account/* + /auth/passkeys/* (register) routes. State-changing POSTs additionally require the double-submit CSRF token and a same-origin Origin/Referer; sensitive mutations (password, passkey removal, identity unlink) require a session authenticated within the last 5 minutes else R402_AUTH_FRESHNESS_REQUIRED. Machine clients use the /auth/v1/* JWT routes instead.
    controlPlaneSession:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: 'Principal-bound control-plane session bearer minted by control-plane login (passkey / email magic-link / Google / GitHub). Payload: typ=run402.control-plane-session+jwt, aud=run402.control-plane.v1, token_use=control_plane_session. WRITE-capable subject to org role + step-up (passkey-principals-onboarding).'
    controlPlaneBrowserSession:
      type: apiKey
      in: cookie
      name: __Host-Http-r402_cp_session
      description: Opaque control-plane browser session handle. It is distinct from the bearer token and tenant browser session, rotates on refresh, and is accepted only on its documented same-origin browser routes and explicit principal-transport surfaces.
    grantKeyBearer:
      type: http
      scheme: bearer
      bearerFormat: run402_agent_key
      description: Scoped Run402 grant key bearer (a run402_agent_key minted against one grant). The route declares the required project capability, such as `project.archives.export` or `project.deploy`; a grant key never grants owner-only operations.
    voucherIssuerKey:
      type: apiKey
      in: header
      name: x-run402-issuer-key
      description: Issuer credential for minting and listing vouchers. Held by a registered voucher-issuing application; provisioned by platform staff. Not a tenant credential — agents never hold one.
    gitBasicAuth:
      type: http
      scheme: basic
      description: 'Git smart HTTP on app repos: HTTP Basic auth whose password is the project''s service key (or project credential) or a grant key for the project; the username is ignored. A request without credentials gets 401 with `WWW-Authenticate: Basic realm="run402"`, so git asks its credential helper. `run402 app-repos clone <repo_name>` installs a helper that supplies the local project''s service key, so no secret lands in the remote URL or .git/config.'