# Registration and Offers Register customers, upload documentation, complete biometrics, and receive credit offers. ## Flow Overview Two processes happen in parallel: the **credit analysis** (starts automatically upon registration) and **KYC verification** (the customer completes at their own pace). ![Customer lifecycle](/assets/customer-lifecycle.1b5d384fc5fb4f45263b89ccc2357e528fd2ac6a27ea23ba0f31c471e699bc76.53e9d79f.svg) | Status | Description | | --- | --- | | `pending_kyc` | Customer created, awaiting documentation and biometrics | | `under_review` | Documents submitted, analysis in progress | | `active` | Verified and eligible for credit offers | ## Create a Customer Register the business with Dinie. The `external_id` field is the internal reference from your system that you will use to identify the customer. ```typescript Node.js const customer = await client.customers.create({ externalId: "partner-ref-123", // Your internal ID cpf: "123.456.789-00", // Partner's CPF name: "Joao Silva", email: "joao@example.com", phone: "+5511999999999", cnpj: "12.345.678/0001-90", tradingName: "Loja do Joao", }); console.log(customer.status); // "pending_kyc" console.log(customer.kyc); // Pending verification items ``` ```ruby Ruby customer = client.customers.create( external_id: "partner-ref-123", # Your internal ID cpf: "123.456.789-00", # Partner's CPF name: "Joao Silva", email: "joao@example.com", phone: "+5511999999999", cnpj: "12.345.678/0001-90", trading_name: "Loja do Joao" ) puts customer.status # "pending_kyc" puts customer.kyc # Pending verification items ``` ```python Python customer = client.customers.create( external_id="partner-ref-123", # Your internal ID cpf="123.456.789-00", # Partner's CPF name="Joao Silva", email="joao@example.com", phone="+5511999999999", cnpj="12.345.678/0001-90", trading_name="Loja do Joao", ) print(customer.status) # "pending_kyc" print(customer.kyc) # Pending verification items ``` ```bash cURL curl -X POST https://sandbox.api.dinie.com.br/v3/customers \ -H "Authorization: Bearer dinie_at_..." \ -H "Content-Type: application/json" \ -d '{ "external_id": "partner-ref-123", "cpf": "123.456.789-00", "name": "Joao Silva", "email": "joao@example.com", "phone": "+5511999999999", "cnpj": "12.345.678/0001-90", "trading_name": "Loja do Joao" }' ``` > **Info:** If you create a customer with the same CPF/CNPJ and `external_id`, the API returns the existing customer (idempotent). A `409` error only occurs when the `external_id` differs for the same CPF/CNPJ. ## Upload Documents Upload the documents listed in the `customer.kyc` array right after registration to speed up the analysis: ```typescript Node.js import fs from "fs"; await client.customers.uploadDocument(customer.id, { type: "ccmei", file: fs.createReadStream("/path/to/ccmei.pdf"), }); await client.customers.uploadDocument(customer.id, { type: "selfie", file: fs.createReadStream("/path/to/selfie.jpg"), }); ``` ```ruby Ruby client.customers.upload_document( customer.id, type: "ccmei", file: File.open("/path/to/ccmei.pdf") ) client.customers.upload_document( customer.id, type: "selfie", file: File.open("/path/to/selfie.jpg") ) ``` ```python Python client.customers.upload_document( customer.id, type="ccmei", file=open("/path/to/ccmei.pdf", "rb"), ) client.customers.upload_document( customer.id, type="selfie", file=open("/path/to/selfie.jpg", "rb"), ) ``` ```bash cURL curl -X POST "https://sandbox.api.dinie.com.br/v3/customers/${CUSTOMER_ID}/documents" \ -H "Authorization: Bearer dinie_at_..." \ -F "type=ccmei" \ -F "file=@/path/to/ccmei.pdf" curl -X POST "https://sandbox.api.dinie.com.br/v3/customers/${CUSTOMER_ID}/documents" \ -H "Authorization: Bearer dinie_at_..." \ -F "type=selfie" \ -F "file=@/path/to/selfie.jpg" ``` Supported formats: **PDF**, **JPEG**, **PNG**. Only upload the types listed in the `kyc` array -- unrecognized types return a `422` error. ## Receive the Credit Offer The credit analysis starts automatically upon registration. When Dinie generates an offer, you receive the `credit_offer.available` webhook: ```typescript Node.js app.post("/webhooks/dinie", express.raw({ type: "application/json" }), (req, res) => { const event = client.webhooks.unwrap(req.body.toString(), req.headers); if (event.type === "credit_offer.available") { const externalId = event.data.external_id; const amount = event.data.approved_amount; notifyCustomer(externalId, `Credit offer of R$ ${amount} available`); } res.sendStatus(200); }); ``` ```ruby Ruby post "/webhooks/dinie" do event = client.webhooks.unwrap(request.body.read, request.env) if event["type"] == "credit_offer.available" external_id = event.dig("data", "external_id") amount = event.dig("data", "approved_amount") notify_customer(external_id, "Credit offer of R$ #{amount} available") end status 200 end ``` ```python Python @app.post("/webhooks/dinie") async def handle_webhook(request: Request): event = client.webhooks.unwrap(await request.body(), request.headers) if event["type"] == "credit_offer.available": external_id = event["data"]["external_id"] amount = event["data"]["approved_amount"] notify_customer(external_id, f"Credit offer of R$ {amount} available") return Response(status_code=200) ``` ```bash cURL # Webhooks are received via POST at your configured endpoint. # Example credit_offer.available payload: # { # "type": "credit_offer.available", # "data": { # "id": "co_550e8400...", # "customer_id": "cust_550e8400...", # "external_id": "partner-ref-123", # "approved_amount": "50000.00", # "interest_rate": 3.5 # } # } ``` ## Next Step When the customer has `active` status and an available offer, they are ready to proceed. Continue to the [Simulation and Loan Origination](/guides/credit-workflow) guide.