View Source Changelog
All notable changes to this project are documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
Unreleased
0.2.0 - 2026-09-02
Coverage and packaging since the first Hex release. Breaking for inbound
webhooks: add ex_pipedrive_web if you used
ExPipedrive.Incoming.Handler from core.
Added
- Run Dialyzer in CI on the primary Elixir 1.17 matrix cell with PLT caching;
document
mix dialyzerin the local quality gate (#84). - Optional sibling package
ex_pipedrive_phoenix(packages/ex_pipedrive_phoenix) for marketplace OAuth install helpers (independent of Überauth) (#21). - Optional sibling package
ex_pipedrive_oban(packages/ex_pipedrive_oban) with cursor-aware Oban sync workers and rate-limit snooze (#20). - Optional sibling package
ex_pipedrive_web(packages/ex_pipedrive_web) with inbound webhook Plug helpers; Event structs stay in core (#82). - Expand
ExPipedrive.Webhook.Eventbeyond deal/person: typed decode for organization, activity, lead, note, product, pipeline, stage, user, activityType, deal_product, deal_installment, project, task, and board; v1mergedplus v2create/change/delete; real v2 payloads synthesize an event name frommeta.action/meta.entity; unknown resources stay maps (#81).
Fixed
ExPipedrive.Users.find_users_by_name/3matched atom-key response bodies (%{success: true, data: data}) and silently returned no matches against Jason-decoded (string-key) JSON. Now matches%{"data" => data}like every other resource module (#67).- Preserve API-provided lead value currencies and leave bare numeric values currency-less.
Changed
- Inbound webhook Plug —
ExPipedrive.Incoming.Handlermoved to sibling packageex_pipedrive_webasExPipedriveWeb.Incoming.Handler(old module names remain compatibility aliases there). Core no longer depends on Plug (#82). - Facade / twin cleanup — Document blessed path (
ExPipedrive.Deals.get/2,list_page/2,stream/2, …). Soft-deprecate legacy v1 twin names on resource modules and the root facade; nothing removed yet (#79). - Resource adoption —
Deals,Persons,Organizations,Activities, andPipelinesimplementExPipedrive.Resourcefor v2 CRUD/list/stream (same pattern as Products/Stages). Public APIs unchanged; v1 legacy helpers retained (#78). - List return shapes —
Notes.get_all_org_notes/2now returns{:ok, %PagedResult{}}likeNotes.list/2(was a bare note list). Preferlist/2with:org_id. Documented list conventions onExPipedrive.Page; soft-documentedPipelines.list_pipelines/1in favor oflist_page/2/stream/2(#86). - Refresh AUDIT.md as a current Pipedrive OpenAPI gap map (implemented vs missing tags); catch-all checklist split into focused issues (#83, #88).
Added
ExPipedrive.ProjectsandExPipedrive.ProjectBoards(API v2): CRUD plus cursor list/stream for projects (including archived list), and full board lifecycle on/api/v2/boards; typedExPipedrive.ProjectandExPipedrive.ProjectBoard. Phases, templates, fields, search, and archive actions deferred (#105).ExPipedrive.Tasks(API v2, beta):list_page/2/stream/2,get/2,create/2,update/3, anddelete/2against/api/v2/tasks; typedExPipedrive.Task(#106).ExPipedrive.DealInstallments(API v2, Growth+ plans):list_page/2/stream/2(requires:deal_ids),create/3,update/4, anddelete/3against/api/v2/deals/installmentsand/api/v2/deals/:id/installments; typedExPipedrive.DealInstallment(#103).ExPipedrive.LeadFieldsandExPipedrive.LeadSources(API v1):list/2/stream/2over/api/v1/leadFields(offset pagination, reusingExPipedrive.Field) andlist/1over/api/v1/leadSources(fixed source names viaExPipedrive.LeadSource) (#104).ExPipedrive.NoteFields(API v1):list/1(pluslist_note_fields/1alias) over/api/v1/noteFields; reusesExPipedrive.Field(#107).ExPipedrive.DealProducts(API v2):list_page/3/stream/3, client-sideget/3,create/3,update/4(PATCH),delete/3, anddelete_many/3against/api/v2/deals/:id/products; typedExPipedrive.DealProduct(#102).- Expand
ExPipedrive.ActivityTypes(API v1):list/1(pluslist_activity_types/1alias), client-sideget/2,create/2,update/3,delete/2against/api/v1/activityTypes;ActivityTypegainsorder_nr/icon_key/color(#87). - Admin / meta APIs (v1 read-first)
(#77):
ExPipedrive.Currencies(list/get/get_by_codeover/api/v1/currencies),ExPipedrive.Recents(listover/api/v1/recents),ExPipedrive.Roles(list/get/assignments/pipelines/ settings),ExPipedrive.PermissionSets(list/get/assignments), andExPipedrive.Teamsagainst/api/v1/legacyTeams(list/get/users/ list_for_user). Role/team writes deferred toRaw. ExPipedrive.Mailbox(API v1):list_threads/2,get_thread/2,list_thread_messages/2,get_message/3,update_thread/3,delete_thread/2against/api/v1/mailbox/{mailThreads,mailMessages}; typedExPipedrive.MailThread,MailMessage, andMailMessagePartystructs (mail:read/mail:fullOAuth scopes) (#74).ExPipedrive.Goals(API v1):list/2(GET /api/v1/goals/findwith dot-notation filter options),create/2,update/3,delete/2, andget_result/4(a goal's progress for a period) against/api/v1/goals; typedExPipedrive.Goalstruct with string ids and plain-maptype/assignee/expected_outcome/duration(Pipedrive has no single-goalgetendpoint) (#75).ExPipedrive.ActivityFieldsandExPipedrive.ProductFields(API v2):list_page/2/stream/2over/api/v2/{activity,product}Fields, matching the existing Deal/Person/Organization field modules;ExPipedrive.Fieldsresolves custom-field hashes/labels for both (#72).- Followers, deal participants, and organization relationships
(#73):
ExPipedrive.Followers(API v2) manages followers on deals, persons, and organizations via the sharedGET/POST/DELETE /api/v2/{deals,persons,organizations}/:id/followersshape, with cursorlist_page/4/stream/4and per-entity convenience wrappers;ExPipedrive.DealParticipantsis an API v1 shim over/api/v1/deals/:id/participants(ExPipedrive.DealParticipantis distinct from the existingActivityParticipant, which decodes activity payloads);ExPipedrive.OrganizationRelationshipsis an API v1 client over/api/v1/organizationRelationships(parent/related org hierarchies). ExPipedrive.ProductVariations(API v2):list_page/3,stream/3,get/3(client-side, since Pipedrive has no single-variation endpoint),create/3,update/4,delete/3against the nested/api/v2/products/:id/variationsAPI; typedExPipedrive.ProductVariationstruct (#71).ExPipedrive.CallLogs(API v1):list/2,get/2,create/2,add_recording/4(multipart audio upload),delete/2against/api/v1/callLogs; typedExPipedrive.CallLogstruct with string ids (Pipedrive does not expose a call log update endpoint) (#76).ExPipedrive.Files(API v1): list/get/upload/download/update/delete plus Google Drivecreate_remote/2andremote_link/2; multipart uploads viaTesla.Multipartwith deal/person/org/activity/product/lead/project link fields (#68).- Labels API (#70):
ExPipedrive.DealLabels,PersonLabels,OrganizationLabelsmanage label definitions via the API v2label_idsfield-options bulk endpoints (POST/PATCH/DELETE /api/v2/{deal,person,organization}Fields/label_ids/options);ExPipedrive.LeadLabelsis an API v1 shim over the dedicated/leadLabelsendpoint;ExPipedrive.Labelsfacade delegates across all four. TypedExPipedrive.Labelstruct. Assigning/clearing labels on an entity remains a normallabel_idswrite via that entity's ownupdate/3— there is no separate assign/clear endpoint. ExPipedrive.Filters(API v1):list/2,get/2,create/2,update/3,delete/2against/api/v1/filters;conditionsaccepted as a plain map (#69).ExPipedrive.Users(API v1):me/1,get/2,list/2(offset pagination), plus fake-server fixtures and tests forme/get/list/find_users_by_name(#67).
0.1.0 - 2026-07-31
First Hex release of ExPipedrive, a v2-first fork of LineDrive.
Added
Client foundation
- Pipedrive API v2 client foundation (
Client,Request, default/api/v2; explicitapi_version: :v1where needed) - Header API token auth (
x-api-token); legacy query auth viaauth: :query - Structured
ExPipedrive.Error/Responsemapping Page/Cursor.streamfor cursor pagination (limit clamped to 500)- OAuth
Tokenbundles,ensure_fresh, pluggableTokenStore(no Ecto in core) - Rate-limit aware retry middleware + request telemetry
(
ExPipedrive.Middleware.Retry,ExPipedrive.Middleware.Telemetry,ExPipedrive.RateLimit); Client opts:retry,:telemetry,:middleware ExPipedrive.Resourcebehaviour + CRUD/list/stream helpers;ProductsandStagesadopt the patternExPipedrive.Raw.request/4escape hatch for unsupported endpoints
Resources (API v2 unless noted)
- Deals and Persons: list/stream (cursor), get, create, update; deal delete
- Organizations, Activities, Pipelines, Stages, Products: list/stream, get, create, update, delete (product variations deferred)
- Search:
ExPipedrive.Searchover/api/v2/itemSearchwith cursor pages/stream and typedSearchResult - Deal, Person, and Organization Fields list/page/stream plus
ExPipedrive.Fieldsfor resolving custom-field hashes and labels - Leads / Notes: explicit API v1 shims with map-based create helpers and
get/2,create/2,list/2aliases - Webhooks:
ExPipedrive.Webhookssubscription list/create/delete (API v1 management);Webhook.Event/Webhook.Handlerinbound surface (optional Plug; Basic auth; package extract deferred)
Docs & tooling
- Fake Pipedrive server fixtures for v2 resources used in tests
- MVP README flows: stream open deals; create person then deal
- CI matrix, ExDoc, Hex publish-on-release workflow
Changed
- Package / OTP app / modules rebranded from LineDrive →
ex_pipedrive/ExPipedrive - Core deps slimmed (Timex removed; Plug optional for webhooks only)
- Silent OTP Application/Registry coupling removed
Migrating from LineDrive
- Depend on
{:ex_pipedrive, "~> 0.1.0"}instead of:line_drive. - Rename modules
LineDrive.*→ExPipedrive.*. - Prefer
ExPipedrive.client/2(header token) and v2 helpers (Deals.stream/2,Deals.create/2,Persons.create/2, …) over legacy v1 list APIs. - OAuth: persist
ExPipedrive.Oauth.Tokenvia yourTokenStoreimplementation; build clients withClient.from_token/2orfrom_token_store/4. - Use
ExPipedrive.Raw.request/4for endpoints not yet wrapped.