Upload Documents and Proofs

Declare supporting documents for an entity and upload the files (proofs) that Localpayment reviews during KYC/KYB.

A document is the declared data (type and number). A proof is a file that supports it. This guide shows how to add documents to an entity, upload their files one by one, replace or remove files, and check that every document is covered so the entity is ready for review.

Prerequisites

  • An entity created with Create an Entity, and the documentId of each of its documents.
  • Files in JPG, PNG, or PDF, up to 10 MB each.

Files per document

A document holds as many files as you need. Each file has a type:

proofTypeTypical useBehavior on a new upload
FRONTFront side of an identity document, or the single image of a document.Replaces the current file, which becomes SUPERSEDED.
BACKBack side of an identity document.Replaces the current file, which becomes SUPERSEDED.
SELFIEPhoto of the person, uploaded on the identity document itself.Replaces the current file, which becomes SUPERSEDED.
DOCUMENTScanned document (PDF): proof of address, articles of incorporation, tax registration.Adds a file, for example each page of a contract.
OTHERAny other evidence.Adds a file.

An APPROVED file cannot be replaced (409 PROOF_APPROVED). A file uploaded by mistake can be removed with Delete a Proof while it is not approved.

%%{init: {'theme': 'base', 'themeVariables': {'background': '#ffffff', 'primaryColor': '#31467c', 'primaryTextColor': '#ffffff', 'primaryBorderColor': '#0c1a29', 'secondaryColor': '#31467c', 'tertiaryColor': '#ffffff', 'lineColor': '#0c1a29', 'textColor': '#0c1a29', 'edgeLabelBackground': '#ffffff', 'fontFamily': 'Manrope'}, 'fontFamily': 'Manrope', 'htmlLabels': false, 'flowchart': {'htmlLabels': false, 'wrappingWidth': 400, 'padding': 20}}}%%
flowchart TD
    A["Your backend<br/>POST /api/entity/v1/entities/{entityId}/documents<br/>PROOF_OF_ADDRESS"] --> B["Entities API<br/>201: documentId"]:::lp
    B --> C["Your backend<br/>POST /api/entity/v1/documents/{docId}/proofs?proofType=FRONT<br/>multipart file"]
    C --> D["Entities API<br/>201: proof id, verificationStatus PENDING"]:::lp
    D --> E["Your backend<br/>POST /api/entity/v1/documents/{docId}/proofs?proofType=DOCUMENT<br/>PDF"]
    E --> F["Entities API<br/>201: proof id"]:::lp
    F --> G["Your backend<br/>GET /api/entity/v1/entities/{entityId}/kyc-status"]
    G --> H["Entities API<br/>200: documentationStatus COMPLETE"]:::lp
    classDef default fill:#31467c,stroke:#0c1a29,stroke-width:1px,color:#ffffff,font-family:Manrope
    classDef lp fill:#0c1a29,stroke:#0c1a29,color:#ffffff
    classDef terminal fill:#0c1a29,stroke:#0c1a29,color:#ffffff
    classDef lbl fill:#0c1a29,stroke:#0c1a29,color:#ffffff,font-size:13px

Step by step

  1. Declare the document if the entity does not have it yet, with Add a Document. Keep its documentId.
  2. Upload the file with Upload a Proof: POST /api/entity/v1/documents/{docId}/proofs?proofType=FRONT as multipart/form-data, with a part named file.
  3. Check the upload: the 201 response must show sizeBytes greater than zero and the expected mimeType.
  4. Repeat for the back (proofType=BACK) and the selfie (proofType=SELFIE) of the identity document, and for each other document.
  5. Check coverage with Get KYC Status. documentationStatus must be COMPLETE so the entity is ready for review.

Upload a file

curl -X POST "https://api.stage.localpayment.com/api/entity/v1/documents/2e16d844-4fa9-4295-9a21-83ec32ef241a/proofs?proofType=FRONT" \
  -H "Authorization: Bearer $LOCALPAYMENT_ACCESS_TOKEN" \
  -F "file=@id_front.jpg;type=image/jpeg"
{
  "id": "2c4c2f74-7179-4113-83fb-f11dbce9e07d",
  "documentId": "2e16d844-4fa9-4295-9a21-83ec32ef241a",
  "proofType": "FRONT",
  "fileName": "id_front.jpg",
  "mimeType": "image/jpeg",
  "sizeBytes": 102400,
  "verificationStatus": "PENDING",
  "verifiedBy": null,
  "verifiedAt": null,
  "verificationReason": null,
  "uploadedBy": "12345",
  "uploadedAt": "2024-01-15T17:03:13Z",
  "status": "CURRENT",
  "supersededAt": null,
  "supersededBy": null,
  "replacedByProofId": null,
  "deletedAt": null,
  "deletedBy": null,
  "inVerification": false
}

In Python, check the size of the stored file and handle the upload errors:

import os
import requests

BASE_URL = "https://api.stage.localpayment.com/api/entity"
access_token = os.environ["LOCALPAYMENT_ACCESS_TOKEN"]
doc_id = "2e16d844-4fa9-4295-9a21-83ec32ef241a"

with open("id_front.jpg", "rb") as f:
    response = requests.post(
        f"{BASE_URL}/v1/documents/{doc_id}/proofs",
        params={"proofType": "FRONT"},
        files={"file": ("id_front.jpg", f, "image/jpeg")},
        headers={"Authorization": f"Bearer {access_token}"},
        timeout=60,
    )

if response.status_code == 201:
    proof = response.json()
    if proof["sizeBytes"] == 0:
        raise RuntimeError("Empty file stored: upload again with the same proofType")
elif response.status_code in (413, 415):
    raise RuntimeError("Use a JPG, PNG, or PDF file of 10 MB or less")
elif response.status_code == 502:
    pass  # STORAGE_WRITE_FAILED: retry the upload
else:
    problem = response.json()
    # 409 PROOF_APPROVED or ENTITY_IN_REVIEW: the file cannot be replaced now
    raise RuntimeError(f"{problem.get('code')} correlationId={problem.get('correlationId')}")

Check coverage

KYC status once both files are in place:

{
  "entityId": "5aced5da-40c1-4bec-85ff-c8cd1bcb4526",
  "status": "PENDING_KYC",
  "documentationStatus": "COMPLETE",
  "statusReason": null,
  "documents": [
    {
      "documentId": "2e16d844-4fa9-4295-9a21-83ec32ef241a",
      "type": "CPF",
      "status": "PENDING",
      "proofs": [
        {
          "proofId": "2c4c2f74-7179-4113-83fb-f11dbce9e07d",
          "verificationStatus": "PENDING"
        }
      ]
    },
    {
      "documentId": "e0ea9515-442e-4bc5-bc82-b8d278255c37",
      "type": "PROOF_OF_ADDRESS",
      "status": "PENDING",
      "proofs": [
        {
          "proofId": "acb78b3f-fe18-4094-b6a9-2107f502d709",
          "verificationStatus": "PENDING"
        }
      ]
    }
  ]
}

Read files back

Get a Proof returns the metadata and a downloadUrl valid for 10 minutes. Download a Proof File redirects straight to it. Both are audited with the user in your access token.

⚠️

The signed downloadUrl grants access to the file until it expires. Do not store it or share it with third parties. Request a new one when you need the file again.

Replace a rejected file

When Compliance rejects a proof, the document becomes REJECTED and verificationReason explains why:

{
  "documentId": "0266257c-a2aa-49ac-99fe-b3882a51d750",
  "entityId": "8f5b2c9a-1caf-4b2c-b085-82bbaead6ddd",
  "type": "NATIONAL_ID",
  "id": "00.000.000-0",
  "issuingCountry": "BRA",
  "issueDate": null,
  "expirationDate": null,
  "isPrimary": false,
  "status": "REJECTED",
  "metadata": null,
  "proofs": [
    {
      "id": "931398af-9c77-4958-abf8-4c749147c508",
      "documentId": "0266257c-a2aa-49ac-99fe-b3882a51d750",
      "proofType": "BACK",
      "fileName": "id_back.jpg",
      "mimeType": "image/jpeg",
      "sizeBytes": 98304,
      "verificationStatus": "REJECTED",
      "verifiedBy": "67890",
      "verifiedAt": "2024-01-15T17:20:34Z",
      "verificationReason": "Illegible image",
      "uploadedBy": "12345",
      "uploadedAt": "2024-01-15T17:19:49Z",
      "status": "CURRENT",
      "supersededAt": null,
      "supersededBy": null,
      "replacedByProofId": null,
      "deletedAt": null,
      "deletedBy": null,
      "inVerification": false
    }
  ],
  "createdAt": "2024-01-15T17:19:46Z",
  "updatedAt": "2024-01-15T17:19:46Z"
}

Once the entity is back in PENDING_KYC, upload a new file with the same proofType. The rejected proof is replaced and the document returns to PENDING. When the corrections are done, call Request Verification again.

Edit a document

Update a Document changes the issuing country, the dates, and the metadata. Any change resets the document's approved proofs to PENDING. The type and number are immutable: add a new document and delete the old one instead. The primary document cannot be deleted.

Common errors

ErrorCauseFix
413 FILE_TOO_LARGEFile larger than 10 MB.Compress or split the file.
415 UNSUPPORTED_FILE_TYPEThe file is not a JPG, PNG, or PDF.Convert the file and upload it again.
400 VALIDATION_ERRORMissing or invalid proofType.Check the query string.
409 PROOF_APPROVEDThe file you are replacing or deleting is already approved.Keep it. Upload additional evidence as DOCUMENT or OTHER.
409 ENTITY_IN_REVIEWThe entity is under review: no file can be uploaded, replaced, or deleted.Wait for the outcome in Get KYC Status.
409 ENTITY_NOT_EDITABLEThe entity is REJECTED, BLOCKED, or CLOSED.Files cannot be added to that entity.
201 with sizeBytes 0The multipart request had no file part.Attach the file and upload again with the same proofType.

Next steps


Did this page help you?