> ## Documentation Index
> Fetch the complete documentation index at: https://docs.api.nkama.ga/llms.txt
> Use this file to discover all available pages before exploring further.

# Sign a document

> Records a signature in the given capacity once the one-time code from the sign/otp step verifies. Signing an already-signed document is idempotent; voided documents cannot be signed.



## OpenAPI

````yaml /api-reference/openapi.json post /api/v1/documents/{id}/sign
openapi: 3.1.0
info:
  contact:
    email: api@nkama.ga
    name: NKAMA Engineering
  description: |-
    REST API for the NKAMA property rental and management platform (Gabon).

    All amounts are in XAF minor units and all timestamps are UTC (ISO-8601).
    Every request must carry a bearer access token; data is isolated per
    organization via the token's `org_id` claim, so a caller only ever sees
    their own organization's resources.
  license:
    name: Proprietary
  title: NKAMA API
  version: v1
servers:
  - description: Sandbox
    url: https://sandbox.api.nkama.ga
  - description: Production
    url: https://api.nkama.ga
  - description: Local development
    url: http://localhost:8080
security:
  - bearer-jwt: []
tags:
  - description: >-
      Authenticated self-service for the signed-in user, including changing the
      phone number (the login identifier) after re-verifying the new number by
      OTP.
    name: Account
  - description: >-
      Read generated lease contracts and invoice documents, fetch short-lived
      download URLs and record signatures. Documents are produced automatically
      from booking and billing events, so there is no create endpoint.
    name: Documents
  - description: >-
      Vendor callbacks. Not for client use: authenticated by a shared secret
      and/or an HMAC-SHA256 signature configured with the vendor, not a bearer
      token.
    name: Webhooks
  - description: >-
      Public, pre-authentication phone-first sign-up: request an OTP for a phone
      number, verify it for a short-lived ticket, then redeem the ticket with a
      profile to create the account. No bearer token — the caller has no account
      yet.
    name: Registration
  - description: >-
      Authenticated verification of the caller's on-file number: the code is
      always sent to the number the mirror holds for the caller, never one from
      the request, so a caller can only verify their own number.
    name: Phone verification
  - description: >-
      Public, pre-authentication forgotten-password reset: request an OTP to a
      registered number, then submit the code with a new password. The request
      response is uniform whether or not the number has an account, so it never
      reveals which numbers are registered.
    name: Account recovery
  - description: >-
      Currently-required Terms of Service and Privacy Policy versions to display
      and accept at sign-up.
    name: Legal
paths:
  /api/v1/documents/{id}/sign:
    post:
      tags:
        - Documents
      summary: Sign a document
      description: >-
        Records a signature in the given capacity once the one-time code from
        the sign/otp step verifies. Signing an already-signed document is
        idempotent; voided documents cannot be signed.
      operationId: sign
      parameters:
        - description: Document id
          in: path
          name: id
          required: true
          schema:
            format: uuid
            type: string
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SignDocumentRequest'
        required: true
      responses:
        '200':
          content:
            '*/*':
              schema:
                $ref: '#/components/schemas/DocumentResponse'
          description: The document, now signed
        '401':
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
          description: Missing or invalid bearer token
        '403':
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
          description: Authenticated but lacking the required role
        '404':
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
          description: No such document in this organization
        '410':
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
          description: The signing challenge is unknown or expired
        '422':
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
          description: The code is wrong, or the document is void and cannot be signed
        '429':
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ProblemDetail'
          description: Too many wrong codes; the challenge is locked out
components:
  schemas:
    SignDocumentRequest:
      description: Request to record a signature on a document, gated by a one-time code.
      properties:
        challengeId:
          description: Signing challenge id from the sign/otp step
          minLength: 1
          type: string
        code:
          description: One-time code the signer received
          minLength: 1
          pattern: \d{4,8}
          type: string
        role:
          description: Capacity in which the party signs
          enum:
            - LANDLORD
            - MANAGER
            - TENANT
          type: string
      required:
        - challengeId
        - code
        - role
      type: object
    DocumentResponse:
      properties:
        certificateRef:
          type: string
        certifiedOn:
          format: date
          type: string
        certifyingAuthority:
          enum:
            - POLICE
            - MAIRIE
            - NOTARY
            - NONE
          type: string
        documentType:
          enum:
            - NATIONAL_ID
            - PASSPORT
            - RESIDENCE_PERMIT
            - DRIVER_LICENSE
          type: string
        expiresOn:
          format: date
          type: string
        id:
          format: uuid
          type: string
        mediaObjectId:
          format: uuid
          type: string
        role:
          enum:
            - SELF_ID
            - PROOF_OF_OWNERSHIP
            - ATTESTATION
            - OWNER_MANDATE
            - OWNER_ID
            - OTHER
          type: string
      type: object
    ProblemDetail:
      properties:
        detail:
          type:
            - string
            - 'null'
        instance:
          format: uri
          type:
            - string
            - 'null'
        properties:
          additionalProperties: {}
          type:
            - object
            - 'null'
        status:
          format: int32
          type: integer
        title:
          type:
            - string
            - 'null'
        type:
          format: uri
          type: string
      type: object
  securitySchemes:
    bearer-jwt:
      bearerFormat: JWT
      description: >-
        Bearer access token (JWT) issued by Keycloak or the sandbox token
        endpoint.
      scheme: bearer
      type: http

````