Migrating from v2
If you report your loan book to Sivo v2 (DaaS), moving that integration to v3 is mostly a change of paths and a handful of field names. The flow is the same three steps, with more general names, because v3 covers any receivable and not only loans:
| v2 | v3 |
|---|---|
| Borrower (consumer or business) | Account |
| Loan | Receivable |
| Report | Receivable entry |
Everything else carries over: amounts are still integers in the currency's smallest denomination (Money), dates and durations like "1 month" keep their format (Dates and Times), and every write is still an upsert keyed by an id you assign. Keep the ids you use in v2.
Endpoints
| v2 | v3 |
|---|---|
POST /v1/borrowers/consumers | POST /accounts with type: "individual" |
POST /v1/borrowers/businesses | POST /accounts with type: "business" |
POST /v1/loans | POST /receivables |
POST /v1/reports | POST /receivables/{id}/entries |
A few things also change around the requests:
- Base URL. All v3 requests go to
https://core.sivo.com, with no version prefix. Sandbox and live share this URL; the API key you send picks the environment (see Testing). - Authentication. v3 replaces the OAuth2 refresh/access token exchange with an API key from the developer dashboard, sent as the
Authorizationheader on every request (Authorization: sk_live_...; see Authentication). There is no access token to fetch or refresh. - Partial updates. When you upsert an
idthat already exists, you only need to send the fields that changed (see Updating Data). - Retries. POST requests accept an
IdempotencyKeyheader so you can retry safely (see Idempotent Requests).
Borrowers → accounts
Consumer and business borrowers become one account resource, told apart by type.
| v2 field | v3 field | Notes |
|---|---|---|
id | id | Unchanged. |
| — | type | New and required: individual for a consumer borrower, business for a business borrower. |
first_name, last_name | same names | Unchanged. |
company | name | Businesses: the business name. |
entity_document_id | legal_entity_id | Prefixed with the kind of id: rfc:ABC123456XYZ for a Mexican RFC, ein:123456789 for a US EIN (digits only, no dash), nit:900123456 for a Colombian NIT (the base number without dots or the check digit), nit:1020703023 for a Bolivian NIT, nif:B12345674 for a Spanish NIF, crn:08572260 for a UK Companies House number and bn:123456782 for a Canadian Business Number. A national id must match the account's address country (a nit: needs a CO or BO address); duns: works anywhere. An EIN must start with a prefix the IRS assigns, so a mistyped one like 17-4464132 is rejected. Each legal entity id can belong to only one of your accounts: if v2 has the same company twice, or several locations under one EIN, report them as one account, or send the id on one account only. Omit it when you don't have the id yet instead of sending a placeholder like PENDING. |
address.street | address.street_address | |
address.city | address.locality | |
address.state | address.region | |
address.postal_code, address.country | same names | Unchanged. |
country_code, phone | phone | One field in E.164 format: a +, the country code, then the number. country_code: "57" and phone: "3001234567" become "+573001234567". |
credit_ranking | credit_score | Prefixed with the bureau and zero-padded to 3 digits, like experian:720, datacredito:720 (DataCrédito Experian, Colombia) or transunion:650. A bare score like "430" is rejected; if you don't know which bureau a score comes from, or it's your own internal score, omit it. Omit it too when the borrower has no score. |
industry | industry | A 6-digit NAICS code instead of a named category. See Industry codes below. |
email, website | same names | Unchanged, but now optional. A website is a domain, like https://acme.com, not a page URL like https://acme.com/locations/austin. Omit it when the borrower has none instead of sending your own website. |
is_veteran, date_of_birth, date_of_incorporation | — | No longer collected; drop them from the request. |
For example, this v2 business borrower:
{
"id": "brw-1001",
"company": "Acme Logistics LLC",
"entity_document_id": "12-3456789",
"date_of_incorporation": "2019-04-01",
"address": { "street": "100 Main St", "city": "Austin", "state": "TX", "postal_code": "78701", "country": "US" },
"country_code": "1",
"phone": "5125550100",
"email": "[email protected]",
"website": "https://acme.com",
"industry": "restaurants"
}becomes this v3 account:
{
"id": "brw-1001",
"type": "business",
"name": "Acme Logistics LLC",
"legal_entity_id": "ein:123456789",
"address": { "street_address": "100 Main St", "locality": "Austin", "region": "TX", "postal_code": "78701", "country": "US" },
"phone": "+15125550100",
"email": "[email protected]",
"website": "https://acme.com",
"industry": "722511"
}Industry codes
Use this table to translate the v2 industry categories to NAICS codes. The codes are a reasonable default for each category; if you know a more precise code for a borrower, send that instead (NAICS search).
v2 industry | v3 industry | NAICS title |
|---|---|---|
animal_farming_production | 112990 | All Other Animal Production |
arts_entertainment | 711510 | Independent Artists, Writers, and Performers |
auto_dealers | 441110 | New Car Dealers |
bank_financial_institution | 522110 | Commercial Banking |
beauty_or_barber_shops | 812112 | Beauty Salons (812111 for Barber Shops) |
building_materials_hardware | 444180 | Other Building Material Dealers |
computer_service_repair | 811210 | Electronic and Precision Equipment Repair and Maintenance |
fitness_sports_centers | 713940 | Fitness and Recreational Sports Centers |
health_services | 621999 | All Other Miscellaneous Ambulatory Health Care Services |
industrial_commercial_machinery | 423830 | Industrial Machinery and Equipment Merchant Wholesalers |
insurance | 524210 | Insurance Agencies and Brokerages |
other_education_services | 611699 | All Other Miscellaneous Schools and Instruction |
other_food_services | 722513 | Limited-Service Restaurants |
other_manufacturing | 339999 | All Other Miscellaneous Manufacturing |
other_professional_services | 541990 | All Other Professional, Scientific, and Technical Services |
real_estate | 531210 | Offices of Real Estate Agents and Brokers |
restaurants | 722511 | Full-Service Restaurants |
retail | 459999 | All Other Miscellaneous Retailers |
retail_jeweler_diamonds_gems_gold | 458310 | Jewelry Retailers |
sports_teams_clubs | 711211 | Sports Teams and Clubs |
Loans → receivables
| v2 field | v3 field | Notes |
|---|---|---|
id | id | Unchanged. |
borrower_id | obligor_id | The account that owes the receivable. |
credit_type | product_type | Same values: term_loan, line_of_credit, buy_now_pay_later, and so on. |
delinquent_days | delinquent_since | The date the loan became delinquent (today's date minus delinquent_days). Unlike a day count it doesn't change while the loan stays delinquent, so you don't need to update the loan every day just to increment a counter. Send it together with a delinquent_amount greater than zero (see the rules below). |
receivable_type | — | Removed; drop it from the request. |
program | — | Removed. If you need to keep it with the receivable, send it in metadata, like "metadata": { "program": "1" } (see Metadata). |
funded_by, fund_name, origination_date, currency, term, payment_frequency, interest_rate, credit_limit, origination_fee, periodic_fee, collateral, delinquent_amount, delinquent_times | same names | Unchanged. |
v3 checks a few rules that v2 did not enforce, so a loan v2 accepted can be rejected with 400 Bad Request:
fund_nameis required whenfunded_byisother, and must be omitted forsivoandbalance_sheet.delinquent_timesmust be greater than zero whendelinquent_amountis.delinquent_sinceis required whendelinquent_amountis greater than zero, and must be empty otherwise. v2 accepteddelinquent_dayson its own; in v3, report how much is overdue along with when it became overdue.payment_frequencycannot be longer thanterm.
When a receivable comes out of delinquency, set delinquent_since to null and delinquent_amount to 0. Send the null explicitly: an omitted field is left unchanged (see Updating Data).
Reports → receivable entries
The loan id moves from the body into the path, and the status field is renamed. Entry types keep the same values and meaning.
| v2 field | v3 field | Notes |
|---|---|---|
loan_id | path {id} | POST /receivables/{id}/entries instead of a body field. |
loan_status | receivable_status | Same values: active, closed. |
id, date, type, amount, balance, description | same names | Unchanged. |
A v2 report:
curl -X POST https://dev.sivo.com/v1/reports \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"id": "rep-0001",
"loan_id": "loan-1001",
"date": "2026-08-01",
"type": "disbursement",
"amount": 250000,
"balance": 250000,
"loan_status": "active"
}'becomes this v3 receivable entry:
curl -X POST https://core.sivo.com/receivables/loan-1001/entries \
-H "Authorization: $SIVO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"id": "rep-0001",
"date": "2026-08-01",
"type": "disbursement",
"amount": 250000,
"balance": 250000,
"receivable_status": "active"
}'You can now also remove an entry reported by mistake with DELETE /receivables/{id}/entries/{entry_id}. For the complete account → receivable → entry flow in v3, see the Submit receivables recipe.
Moving your history
v3 calculates your portfolio metrics from the full history of every receivable, just like v2. You don't need to resend the borrowers, loans and reports you already reported in v2: Sivo will help migrate that history to v3. Coordinate the cutover with your Sivo contact so the history is in place before you start sending new activity to v3, and keep the same ids so your new entries line up with the migrated receivables. The history is copied from a snapshot of v2, so once it is in v3, send new activity to v3 only: anything you keep reporting to v2 afterwards has to be migrated again.
Updated 2 days ago

