Generate a Delphi Stripe Client

Stripe publishes and maintains an official OpenAPI 3 description of its API. sgcOpenAPI does not ship a hand written Stripe component, it ships a generator. You run sgcOpenAPI.exe once over that specification and you get a single Pascal unit with one method per operation, a typed response class for every one of them, and a GetOpenAPIClient function that hands you a ready client.

Stripe + sgcOpenAPI

The figures below were measured by running the generator over the current spec3.json and compiling the result, not estimated.

Source spec

openapi/spec3.json in github.com/stripe/openapi, declared as OpenAPI 3.0.0. No conversion step is needed.

What comes out

419 paths become 594 methods and 594 response classes, alongside 1,747 model classes, in one unit of roughly 110,000 lines.

Authentication

Generate with -a 2 and set Authentication.Token.BearerToken at run time. The client then sends Authorization: Bearer on every request.

It compiles

The generated unit builds clean on RAD Studio 12 for Win32 with nothing on the library path except the sgcOpenAPI Source folder.

Run the generator

Download spec3.json from Stripe's public repository, or pass the raw URL straight to -i. Both switches are mandatory, everything else has a default.

> sgcOpenAPI.exe -i "spec3.json" -o "stripe.pas" -a 2

File successfully created stripe.pas

-i takes a local file or a URL and accepts JSON and YAML. -o is the Pascal unit to write, and the unit is named after that file. -a 2 selects token authentication, which is what Stripe's secret key needs. The same executable is also a GUI wizard when you start it with no parameters. The run ends with exit code 0 on success, and a build script can test for 5 (input file), 6 (output file) or 7 (the document could not be turned into a valid OpenAPI 3 document).

Add the generated .pas to your project, put it in a uses clause, and that is the whole integration. There is no component to install, because sgcOpenAPI registers none and ships no design-time package.

Create a charge

Set the secret key once on the client, then call the method the generator named after the operation id. Stripe's operation ids are already valid Pascal identifiers, so PostCharges is exactly what you get.

uses
  stripe;   // the unit you just generated

procedure TfrmStripe.btnChargeClick(Sender: TObject);
var
  oResponse: TsgcOpenAPI_PostCharges_Response;
begin
  GetOpenAPIClient.Authentication.Token.BearerToken :=
    'sk_test_4eC39HqLyjWDarjtT1zdp7dc';

  oResponse := GetOpenAPIClient.PostCharges(
    'amount=2000&currency=usd&source=tok_visa&description=Order+1234');
  try
    if oResponse.IsSuccessful then
      memoLog.Lines.Text :=
        'charge : ' + oResponse.Successful.Id + #13#10 +
        'status : ' + oResponse.Successful.Status + #13#10 +
        'paid   : ' + BoolToStr(oResponse.Successful.Paid, True)
    else
      memoLog.Lines.Text := IntToStr(oResponse.ResponseCode) + ' ' +
        oResponse.ResponseError;
  finally
    oResponse.Free;
  end;
end;

GetOpenAPIClient takes no parameters and returns a client you do not free. The base URL comes out of the servers entry in the specification, so the generated constructor already sets https://api.stripe.com/ and you only override it with -u at generation time or SetBaseURL at run time. The response object is yours, which is why the sample uses a try finally. IsSuccessful is true for status 200 to 299, and ResponseCode and ResponseError carry the rest.

The request body is a form, the response is a class

This is the one thing about Stripe that surprises people, and it comes from the specification rather than from the generator.

var
  oCustomer: TsgcOpenAPI_PostCustomers_Response;
  oSub: TsgcOpenAPI_PostSubscriptions_Response;
begin
  oCustomer := GetOpenAPIClient.PostCustomers(
    'email=jane@example.com&payment_method=pm_card_visa');
  try
    if not oCustomer.IsSuccessful then
      raise Exception.Create(oCustomer.ResponseError);

    oSub := GetOpenAPIClient.PostSubscriptions(
      'customer=' + oCustomer.Successful.Id +
      '&items[0][price]=price_1JxYzZAbCdEfGhIj');
    try
      memoLog.Lines.Add(oSub.Successful.Id);
    finally
      oSub.Free;
    end;
  finally
    oCustomer.Free;
  end;
end;

Every one of the 593 request bodies in Stripe's specification is declared as application/x-www-form-urlencoded, so the generated parameter is const aBody: string and you build the form yourself, in Stripe's own bracket notation. Responses are a different story: they are declared with named schemas, so each one becomes a class you read through properties.

What the generated unit contains

The unit mirrors the document. Nothing is curated, so anything Stripe describes is present and anything Stripe leaves out is not.

One method per operation

594 of them, named from the operation id with any character that cannot appear in a Pascal identifier removed. -m 1 names them from the summary instead, and -m 2 from the endpoint.

One response class per method

TsgcOpenAPI_PostCharges_Response descends from TsgcOpenAPIResponse, carries Successful plus one property per declared error status, and inherits IsSuccessful, ResponseCode and ResponseError.

1,747 model classes

Every schema Stripe declares, including the shared error object, the charge, customer, invoice and subscription objects, and the event payloads.

Query parameters as arguments

Optional query parameters become defaulted arguments in declaration order, so GetCharges takes aCreated, aCustomer, aEnding_before, aExpand, aLimit and the rest without you touching a URL.

Tags as comments

The tags in the document are emitted as comments that group the methods inside the single class. They do not become separate classes, so everything hangs off GetOpenAPIClient.

The documentation from the spec

Stripe's own descriptions are carried through as Pascal comments above each method and property, unless you turn them off.

Four things worth knowing

All four came out of an actual generation run over the current specification.

The unit is large

About 110,000 lines and 5.5 MB. It compiles quickly, but the IDE code editor is slow with a file that size. -x drops operations you list as "VERB endpoint" and -p then removes the classes no remaining operation uses, which is the difference between a unit you can open and one you cannot.

392 warnings, and they are worth reading

Every one of them is about composition. Stripe uses anyOf and oneOf without a discriminator mapping in a lot of places, so the generated class carries one member per branch and your code decides which one was filled. The generator says so per schema rather than picking silently.

The one file upload endpoint has no body

POST /v1/files is the single multipart/form-data operation in the document, and the generated PostFiles takes only aExpand. Upload through TsgcHTTP1Client or the file upload API directly if you need it.

Regenerate when the API version moves

Stripe versions its API and revises the specification often. Pin the spec3.json you generated from, keep it next to your project, and regenerate deliberately. The generator is deterministic, so the same document gives the same unit.

From the blog

OpenAPI Delphi parser

How the reader handles real specifications, including the composition keywords that produce most of the Stripe warnings.

Read post →

OpenAPI parser: bundle schemas

Multi file specifications and external $ref pointers, which are pulled in before the document is read.

Read post →

sgcOpenAPI 2026.6

Release notes for the current version, with the generator options and reader changes.

Read post →
Best value: All-AccessEvery eSeGeCe product, Premium Support included, from €1,059/year.
See All-Access pricing

Generate your Stripe client today

sgcOpenAPI ships the reader, the code generator, the OpenAPI server and pre-built SDKs for Amazon, Azure, Google and Microsoft. One product, three tiers, priced by seat rather than by feature.