> ## Documentation Index
> Fetch the complete documentation index at: https://rubie.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Create credential session

> Start a Rubie-hosted credential collection flow for an end user.

Creates a short-lived hosted form. Open `hosted_url` for the end user (same-tab
redirect is typical), then either wait for their return via `return_url` or poll
[`GET /credential-sessions/{id}`](/api-reference/credential-sessions/get-credential-session)
until `status` is `completed`.

```bash theme={null}
curl -s "$RUBIE_API_URL/api/v1/credential-sessions" \
  -X POST \
  -H "Authorization: Bearer $RUBIE_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: connect-account-42" \
  -d '{
    "strategy_id": "strat_...",
    "return_url": "https://app.example.com/settings/integrations/connected"
  }'
```

## Notes

* `strategy_id` is provisioned by Rubie for your account — one per system you
  connect to.
* `return_url` is optional. If set, its origin must be allowlisted on your
  account. Rubie redirects there with `session_id` appended; confirm the session
  server-side before saving `credential_id`.
* Credentials are validated against the target system on first Blueprint run,
  not when the form is submitted.

See [Hosted credential collection](/guides/hosted-credential-collection) for the
full connect flow, including polling and `return_url` handling.


## OpenAPI

````yaml POST /credential-sessions
openapi: 3.0.3
info:
  title: Rubie API
  version: 1.0.0
  description: >
    Collect end-user credentials through a Rubie-hosted form, then run Rubie

    Blueprints against them asynchronously.


    This API is deliberately thin. Rubie does not model your domain: what a

    Blueprint accepts as input, what it does with a connected system, and what
    it

    produces are all defined by that Blueprint's configuration. The endpoints

    below are the transport around it.


    All endpoints require bearer authentication. Responses use opaque prefixed
    IDs

    (`cred_`, `sess_`, `ecs_`, `strat_`, `run_`, `bp_`), snake_case fields, and
    a

    single top-level error envelope — never a `success` wrapper.
servers:
  - url: https://app.rubiehq.com/api/v1
    description: Production
security:
  - BearerAuth: []
tags:
  - name: Credential Sessions
    description: Start and poll Rubie-hosted credential collection flows.
  - name: Embedded Credential Sessions
    description: Embed a Blueprint picker and credential capture flow in your product.
  - name: Credentials
    description: Revoke vaulted credentials.
  - name: Blueprints
    description: Trigger a Rubie Blueprint run.
  - name: Blueprint Runs
    description: Poll run status and retrieve completed outputs.
paths:
  /credential-sessions:
    post:
      tags:
        - Credential Sessions
      summary: Create a hosted credential session
      description: >
        Creates a short-lived Rubie-hosted credential collection URL for the
        given authentication strategy. Open `hosted_url` for the end user, then
        poll GET until `credential_id` is returned. Credentials are validated
        against the target system on first Blueprint run, not at form submit.
      operationId: createCredentialSession
      parameters:
        - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateCredentialSessionRequest'
      responses:
        '201':
          description: Session created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CredentialSession'
              example:
                id: sess_MQ
                status: pending
                hosted_url: https://app.rubiehq.com/credential-collect/abc123
                return_url: https://app.example.com/settings/integrations/connected
                strategy_id: strat_NQ
                credential_id: null
                expires_at: '2026-08-07T17:00:00.000Z'
                completed_at: null
                created_at: '2026-07-31T17:00:00.000Z'
        '400':
          $ref: '#/components/responses/ValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '422':
          $ref: '#/components/responses/ValidationError'
components:
  parameters:
    IdempotencyKey:
      name: Idempotency-Key
      in: header
      required: false
      schema:
        type: string
      description: >
        Unique key for safely retrying mutating requests. Matching key + body
        replays the original response for 24 hours. Matching key + different
        body returns 409 conflict.
  schemas:
    CreateCredentialSessionRequest:
      type: object
      required:
        - strategy_id
      properties:
        strategy_id:
          type: string
          description: Provisioned authentication strategy id (`strat_...`).
          example: strat_NQ
        name:
          type: string
          maxLength: 256
          description: Optional display name for the vaulted credential shell.
        return_url:
          type: string
          format: uri
          maxLength: 2048
          description: >
            Optional URL to send the end user back to after credential
            collection. Its exact origin (scheme, host, and port) must be
            allowlisted for your account by Rubie. The redirect appends
            `session_id`; confirm the session server-side before saving
            `credential_id`.
          example: https://app.example.com/settings/integrations/connected
      example:
        strategy_id: strat_NQ
        return_url: https://app.example.com/settings/integrations/connected
    CredentialSession:
      type: object
      required:
        - id
        - status
        - strategy_id
        - expires_at
        - created_at
      properties:
        id:
          type: string
          example: sess_MQ
        status:
          $ref: '#/components/schemas/CredentialSessionStatus'
        hosted_url:
          type: string
          nullable: true
          description: >-
            Rubie-hosted form URL. Open for the end user while status is
            pending.
        return_url:
          type: string
          format: uri
          nullable: true
          description: >
            Customer URL supplied when the session was created. After
            collection, Rubie redirects here with `session_id` appended as a
            query parameter.
        strategy_id:
          type: string
          example: strat_NQ
        credential_id:
          type: string
          nullable: true
          example: cred_NDc
          description: >
            Present only when `status` is `completed`, and stable for the life
            of the credential. Retain it against your user record. Do not
            persist an id read from a session in any other status.
        expires_at:
          type: string
          format: date-time
        completed_at:
          type: string
          format: date-time
          nullable: true
        created_at:
          type: string
          format: date-time
    CredentialSessionStatus:
      type: string
      description: >
        Lifecycle status of the session. `completed` always means terminal and
        usable: the credential is vaulted and may be passed to a run. `expired`
        is terminal and not usable. `pending` means the end user has not
        finished the hosted form yet.


        Treat this as an open string set rather than a fixed enum. Additional
        non-terminal statuses may be introduced between collection and
        `completed` — for example while Rubie verifies the credential against
        the target system. Keep polling on any status you do not recognise, and
        only branch on the three values above. Code written as `if (status ===
        "completed") { save(credential_id) }` stays correct.
      enum:
        - pending
        - completed
        - expired
    ErrorResponse:
      type: object
      required:
        - error
      properties:
        error:
          $ref: '#/components/schemas/Error'
    Error:
      type: object
      required:
        - type
        - message
      properties:
        type:
          type: string
          enum:
            - authentication_error
            - authorization_error
            - not_found
            - validation_error
            - conflict
            - rate_limit_exceeded
            - internal_error
        message:
          type: string
        details:
          type: array
          items:
            $ref: '#/components/schemas/ErrorDetail'
    ErrorDetail:
      type: object
      required:
        - message
      properties:
        message:
          type: string
        code:
          type: string
          nullable: true
        field:
          type: string
          nullable: true
  responses:
    ValidationError:
      description: Invalid request
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
    Unauthorized:
      description: Missing or invalid API key
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
    NotFound:
      description: Resource not found in this account
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
    Conflict:
      description: Request conflicts with the current resource state
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      bearerFormat: APIKey
      description: Your Rubie API key as a bearer token.

````