A Go client library for the German Patent and Trademark Office (DPMA) Connect Plus REST API.
DPMA Connect Plus is a paid service requiring authentication:
- Service Details: https://www.dpma.de/recherche/datenabgabe/dpmaconnect/index.html
- Access: Contact DPMA to obtain credentials
- Authentication Method: HTTP Basic Authentication
go get github.com/patent-dev/dpma-connect-pluspackage main
import (
"context"
"fmt"
"log"
dpma "github.com/patent-dev/dpma-connect-plus"
)
func main() {
client, err := dpma.NewClient(&dpma.Config{
Username: "your-dpma-username",
Password: "your-dpma-password",
})
if err != nil {
log.Fatal(err)
}
ctx := context.Background()
// Get service version
version, err := client.GetVersion(ctx, dpma.ServicePatent)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Version: %s\n", version)
// Validate query before sending (optional but recommended)
if err := dpma.ValidatePatentQuery("TI=Elektrofahrzeug"); err != nil {
log.Fatal(err)
}
// Search patents (uses DPMAregister expert search syntax)
results, err := client.SearchPatents(ctx, "TI=Elektrofahrzeug")
if err != nil {
log.Fatal(err)
}
fmt.Printf("Results: %d bytes\n", len(results))
}All methods accept context.Context for timeout and cancellation support.
// Get service version
GetVersion(ctx, service string) (string, error)Use the service constants: dpma.ServicePatent, dpma.ServiceDesign, dpma.ServiceTrademark.
// Validate a query against service-specific field codes (returns nil or error)
ValidatePatentQuery(query string) error
ValidateDesignQuery(query string) error
ValidateTrademarkQuery(query string) errorFor advanced usage (tokenization, field inspection), use the query sub-package directly.
// Search patents and utility models
SearchPatents(ctx, query string) ([]byte, error)
// Get patent info by registered number
GetPatentInfo(ctx, registeredNumber string) ([]byte, error)
// Get searchable full text for a document
GetSearchableFullText(ctx, documentID string) ([]byte, error)
// Download single patent publication PDF
GetPatentPublicationPDF(ctx, documentID string) ([]byte, error)
// Weekly bulk downloads (XML)
GetDisclosureDocumentsXML(ctx, year, week int) ([]byte, error)
GetPatentSpecificationsXML(ctx, year, week int) ([]byte, error)
GetUtilityModelsXML(ctx, year, week int) ([]byte, error)
GetPublicationDataXML(ctx, year, week int) ([]byte, error)
GetApplicantCitationsXML(ctx, year, week int) ([]byte, error)
GetEuropeanPatentSpecificationsXML(ctx, year, week int) ([]byte, error)
// Weekly bulk downloads (PDF)
GetDisclosureDocumentsPDF(ctx, year, week int) ([]byte, error)
GetPatentSpecificationsPDF(ctx, year, week int) ([]byte, error)
GetEuropeanPatentSpecificationsPDF(ctx, year, week int) ([]byte, error)
GetUtilityModelsPDF(ctx, year, week int) ([]byte, error)
// Register extract
GetPatentRegisterExtract(ctx, date time.Time, period string) ([]byte, error)// Search designs
SearchDesigns(ctx, query string) ([]byte, error)
// Get design info by design number
GetDesignInfo(ctx, designNumber string) ([]byte, error)
// Get design image/thumbnail
GetDesignImage(ctx, designNumber, imageNumber string) ([]byte, error)
GetDesignThumbnail(ctx, designNumber, thumbnailNumber string) ([]byte, error)
// Weekly bulk downloads
GetDesignBibliographicDataXML(ctx, year, week int) ([]byte, error)
GetDesignImages(ctx, year, week int) ([]byte, error)
// Register extract
GetDesignRegisterExtract(ctx, date time.Time, period string) ([]byte, error)// Search trademarks
SearchTrademarks(ctx, query string) ([]byte, error)
// Get trademark info by application number
GetTrademarkInfo(ctx, applicationNumber string) ([]byte, error)
// Get trademark image/thumbnail
GetTrademarkImage(ctx, applicationNumber string) ([]byte, error)
GetTrademarkThumbnail(ctx, applicationNumber string) ([]byte, error)
// Weekly bulk downloads
GetTrademarkBibDataApplied(ctx, year, week int) ([]byte, error)
GetTrademarkBibDataRegistered(ctx, year, week int) ([]byte, error)
GetTrademarkBibDataRejected(ctx, year, week int) ([]byte, error)
// Register extract
GetTrademarkRegisterExtract(ctx, date time.Time, period string) ([]byte, error)Every bulk download and register extract method has a *Stream variant that writes to an io.Writer:
// Patent streams
GetDisclosureDocumentsXMLStream(ctx, year, week int, dst io.Writer) error
GetPatentSpecificationsXMLStream(ctx, year, week int, dst io.Writer) error
GetUtilityModelsXMLStream(ctx, year, week int, dst io.Writer) error
GetPublicationDataXMLStream(ctx, year, week int, dst io.Writer) error
GetApplicantCitationsXMLStream(ctx, year, week int, dst io.Writer) error
GetEuropeanPatentSpecificationsXMLStream(ctx, year, week int, dst io.Writer) error
GetDisclosureDocumentsPDFStream(ctx, year, week int, dst io.Writer) error
GetPatentSpecificationsPDFStream(ctx, year, week int, dst io.Writer) error
GetEuropeanPatentSpecificationsPDFStream(ctx, year, week int, dst io.Writer) error
GetUtilityModelsPDFStream(ctx, year, week int, dst io.Writer) error
GetPatentRegisterExtractStream(ctx, date time.Time, period string, dst io.Writer) error
// Design streams
GetDesignBibliographicDataXMLStream(ctx, year, week int, dst io.Writer) error
GetDesignImagesStream(ctx, year, week int, dst io.Writer) error
GetDesignRegisterExtractStream(ctx, date time.Time, period string, dst io.Writer) error
// Trademark streams
GetTrademarkBibDataAppliedStream(ctx, year, week int, dst io.Writer) error
GetTrademarkBibDataRegisteredStream(ctx, year, week int, dst io.Writer) error
GetTrademarkBibDataRejectedStream(ctx, year, week int, dst io.Writer) error
GetTrademarkRegisterExtractStream(ctx, date time.Time, period string, dst io.Writer) errorconfig := &dpma.Config{
Username: "your-username", // Required
Password: "your-password", // Required
BaseURL: "https://dpmaconnect.dpma.de/dpmaws/rest-services", // Default
Timeout: 20 * time.Minute, // Request timeout (default: 20 minutes)
HTTPClient: myCustomHTTPClient, // Optional: provide your own *http.Client
}
client, err := dpma.NewClient(config)ctx := context.Background()
pdf, err := client.GetPatentPublicationPDF(ctx, "DE102023000001A1")
if err != nil {
log.Fatal(err)
}
err = os.WriteFile("patent.pdf", pdf, 0644)
if err != nil {
log.Fatal(err)
}ctx := context.Background()
zipData, err := client.GetDisclosureDocumentsXML(ctx, 2024, 45)
if err != nil {
if _, ok := err.(*dpma.DataNotAvailableError); ok {
fmt.Println("Data not available for this week")
return
}
log.Fatal(err)
}
err = os.WriteFile("disclosure_202445.zip", zipData, 0644)
if err != nil {
log.Fatal(err)
}ctx := context.Background()
file, err := os.Create("patents_202445.zip")
if err != nil {
log.Fatal(err)
}
defer file.Close()
err = client.GetPatentSpecificationsXMLStream(ctx, 2024, 45, file)
if err != nil {
log.Fatal(err)
}ctx := context.Background()
// Validate query against design field codes
if err := dpma.ValidateDesignQuery("INH=Samsung"); err != nil {
log.Fatal(err)
}
results, err := client.SearchDesigns(ctx, "INH=Samsung")
if err != nil {
log.Fatal(err)
}
fmt.Printf("Received %d bytes of XML results\n", len(results))ctx := context.Background()
date := time.Date(2024, 10, 23, 0, 0, 0, 0, time.UTC)
data, err := client.GetPatentRegisterExtract(ctx, date, dpma.PeriodDaily)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Register extract: %d bytes\n", len(data))The query sub-package provides a parser and validator for DPMAregister expert search syntax:
import "github.com/patent-dev/dpma-connect-plus/query"
// Parse and validate a patent query
q, err := query.ParseQuery("TI=Elektrofahrzeug AND INH=Siemens", query.ServicePatent)
if err != nil {
log.Fatal(err)
}
if err := q.Validate(); err != nil {
log.Fatal(err) // e.g. unknown field, unmatched parentheses
}
// Inspect the query
fmt.Println(q.GetFields()) // ["TI", "INH"]
fmt.Println(q.HasField("TI")) // true
// Validate against a specific service
q, _ = query.ParseQuery("MARKE=test", query.ServiceTrademark) // valid
q, _ = query.ParseQuery("MARKE=test", query.ServicePatent) // invalid: unknown field
// Look up field definitions
f, ok := query.GetField("TI", query.ServicePatent)
fmt.Println(f.Description) // "title / designation"
// List all valid fields for a service
fields := query.GetValidFields(query.ServiceDesign)- Tokenizer with support for quoted values, comparison operators (
=,>=,<=,>,<), parentheses, and curly braces (procedure data) - Field validation per service (Patent, Design, Trademark) based on official DPMAregister field codes
- Bracket and brace matching
- Recognizes both English (
AND,OR,NOT) and German (UND,ODER,NICHT) Boolean operators - Field lookup with German name, English description, and input type (text/date)
All search methods use DPMAregister expert search syntax. The format is FIELD=value with Boolean operators AND, OR, NOT.
| Code | Description |
|---|---|
TI |
Title/designation |
INH |
Applicant/proprietor |
IN |
Inventor |
IC |
IPC classification |
AKZ |
File number |
PN |
Publication number |
PUB |
Publication date |
AB |
Abstract |
| Code | Description |
|---|---|
TI |
Designation |
INH |
Proprietor |
ENTW |
Designer |
ERZ |
Product(s) |
WKL |
Commodity class |
RN |
Registration number |
DNR |
Design number |
| Code | Description |
|---|---|
md |
Trademark text |
INH |
Proprietor |
WKL |
Class(es) |
For a full reference, see the DPMAregister help pages:
The library provides custom error types for different scenarios:
// Resource not found (404)
if notFoundErr, ok := err.(*dpma.NotFoundError); ok {
fmt.Printf("Not found: %s %s\n", notFoundErr.Resource, notFoundErr.ID)
}
// Data not available (common for old/future publication weeks)
if _, ok := err.(*dpma.DataNotAvailableError); ok {
fmt.Println("Data not available for the requested period")
}
// Generic API errors
if apiErr, ok := err.(*dpma.APIError); ok {
fmt.Printf("API error: %s (code: %s, HTTP %d)\n", apiErr.Message, apiErr.Code, apiErr.StatusCode)
}
// XML parsing failures (malformed response data)
if xmlErr, ok := err.(*dpma.XMLParseError); ok {
fmt.Printf("Failed to parse response in %s: %v\n", xmlErr.Operation, xmlErr.Unwrap())
}Publication weeks use YYYYWW format (6 digits):
pubWeek, err := dpma.FormatPublicationWeek(2024, 45) // Returns "202445", nil
year, week, err := dpma.ParsePublicationWeek("202445") // Returns 2024, 45, nilRegister extracts use YYYY-MM-DD format:
date := time.Date(2024, 10, 23, 0, 0, 0, 0, time.UTC)
dateStr := dpma.FormatDate(date) // Returns "2024-10-23"DPMA Connect Plus provides three services:
| Service | Description | Constant |
|---|---|---|
| Patents & Utility Models | Patent applications, grants, utility models | dpma.ServicePatent |
| Designs | Design applications and registrations | dpma.ServiceDesign |
| Trademarks | Trademark applications and registrations | dpma.ServiceTrademark |
├── client.go # Core client (Config, NewClient, GetVersion)
├── client_patent.go # Patent service methods
├── client_design.go # Design service methods
├── client_trademark.go # Trademark service methods
├── errors.go # Custom error types
├── helpers.go # Date/week formatting, constants
├── query/ # Query parser and field validation
│ ├── query.go # Parser, tokenizer, validator
│ ├── fields.go # Field definitions per service
│ └── query_test.go # Query package tests
├── client_test.go # Core unit tests
├── client_patent_test.go # Patent unit tests
├── client_design_test.go # Design unit tests
├── client_trademark_test.go # Trademark unit tests
├── integration_test.go # Integration tests (real API)
├── generated/ # Auto-generated OpenAPI code
│ ├── types_gen.go # Generated types
│ └── client_gen.go # Generated client
├── openapi.yaml # OpenAPI 3.0 specification
└── demo/ # Interactive demo application
└── demo.go
This library follows a clean architecture:
- OpenAPI Specification: Hand-crafted
openapi.yamlbased on official DPMA documentation - Code Generation: Types and client generated using oapi-codegen
- Idiomatic Wrapper: Clean Go client wrapping generated code with error handling and convenience methods
Offline tests using mock HTTP server with realistic responses:
go test -v
go test -v -coverTests that make actual requests to the DPMA API:
export DPMA_CONNECT_PLUS_USERNAME=your-username
export DPMA_CONNECT_PLUS_PASSWORD=your-password
go test -tags=integration -vNote: Integration tests require valid DPMA Connect Plus credentials and will skip if environment variables are not set.
An interactive demo application is included:
export DPMA_CONNECT_PLUS_USERNAME=your-username
export DPMA_CONNECT_PLUS_PASSWORD=your-password
cd demo
go run demo.goThe demo provides an interactive menu for testing all three services: patents, designs, and trademarks.
All endpoints defined in the DPMA Connect Plus API are implemented. Verification status depends on the permissions granted to the test account.
The following endpoints have been tested against the live API with real data:
| Service | Endpoint | Description |
|---|---|---|
| General | GetVersion |
Service version info |
| Patent | SearchPatent |
Expert search |
| Patent | GetRegisterInfo |
Register data for a patent |
| Patent | GetFulltextXML / Stream |
Full-text XML |
| Patent | GetFulltextPDF / Stream |
Full-text PDF |
| Patent | GetDocumentIdList |
Document IDs for a publication week |
| Patent | GetBulkFulltextXML / Stream |
Bulk full-text XML |
| Patent | GetBulkFulltextPDF / Stream |
Bulk full-text PDF |
| Patent | GetRegisterExtractXML / Stream |
Register extract |
| Patent | GetDisclosureDocumentsXML / Stream |
Weekly disclosure documents |
| Design | SearchDesign |
Expert search |
| Design | GetDesignRegisterInfo |
Register data for a design |
| Trademark | SearchTrademark |
Expert search |
| Trademark | GetTrademarkRegisterInfo |
Register data for a trademark |
The following endpoints are implemented but could not be verified with the current test account. We are in talks with DPMA to achieve broader test coverage.
| Service | Endpoint | Description |
|---|---|---|
| Patent | GetPublicationDataXML / Stream |
Weekly publication data |
| Patent | GetApplicantCitationsXML / Stream |
Applicant citations |
| Design | GetDesignBibliographicDataXML / Stream |
Bibliographic bulk data |
| Design | GetDesignImages / Stream |
Design images bulk download |
| Trademark | GetTrademarkBibDataApplied / Stream |
Applied trademarks bulk data |
| Trademark | GetTrademarkBibDataRegistered / Stream |
Registered trademarks bulk data |
| Trademark | GetTrademarkBibDataRejected / Stream |
Rejected trademarks bulk data |
- Publication Data: Updated weekly
- Patents/Utility Models: Thursdays
- Designs/Trademarks: Fridays
- Register Data: Updated daily
- Historical Data: Varies by document type
Note: "Data not available" errors are common for:
- Future publication weeks
- Old publication weeks (before digital archiving)
- Weeks with no publications
If the OpenAPI spec is updated:
go install github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen@latest
oapi-codegen -package generated -generate types openapi.yaml > generated/types_gen.go
oapi-codegen -package generated -generate client openapi.yaml > generated/client_gen.gogo fmt ./...
go vet ./...
go test -v ./...Part of the patent.dev open-source patent data ecosystem:
- uspto-odp - USPTO Open Data Portal client (search, PTAB, XML full text)
- epo-ops - EPO Open Patent Services client (search, biblio, legal status, family, images)
- epo-bdds - EPO Bulk Data Distribution Service client
The bulk-file-loader uses these libraries for automated patent data downloads.
MIT License - see LICENSE file for details.
Developed by:
- Wolfgang Stark - patent.dev - Funktionslust GmbH