Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [7.2.0] - 2026-11-05

### Added

- Add `Organization.DownloadManifiestoZipUrlAsync` to obtain a temporary URL for downloading the signed Carta Manifiesto ZIP associated with the organization's certificate RFC.

## [7.1.0] - 2026-10-07

### Added
Expand Down
19 changes: 19 additions & 0 deletions FacturapiTest/WrapperBehaviorTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,25 @@ public async Task OrganizationDeleteSeriesAsync_UsesDeleteSeriesRoute()
Assert.Equal("A", result.Name);
}

[Fact]
public async Task OrganizationDownloadManifiestoZipUrlAsync_UsesExpectedRoute()
{
var handler = new RecordingHandler((request, cancellationToken) =>
{
Assert.Equal(HttpMethod.Get, request.Method);
Assert.NotNull(request.RequestUri);
Assert.Equal("/v2/organizations/org_1/manifiesto/download-url", request.RequestUri.PathAndQuery);
return Task.FromResult(JsonResponse("{\"url\":\"https://storage.googleapis.com/signed-download\",\"expires_at\":\"2030-01-01T00:00:00.000Z\",\"content_type\":\"application/zip\",\"filename\":\"manifiesto_AAA010101AAA.zip\"}"));
});

var wrapper = new OrganizationWrapper("test_key", "v2", CreateHttpClient(handler));
var result = await wrapper.DownloadManifiestoZipUrlAsync("org_1");

Assert.Equal("application/zip", result.ContentType);
Assert.Equal("manifiesto_AAA010101AAA.zip", result.Filename);
Assert.Equal(new DateTimeOffset(2030, 1, 1, 0, 0, 0, TimeSpan.Zero), result.ExpiresAt);
}

[Fact]
public async Task OrganizationListTeamAccessAsync_UsesTeamRoute()
{
Expand Down
12 changes: 12 additions & 0 deletions Models/SignedDownloadUrl.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using System;

namespace Facturapi
{
public class SignedDownloadUrl
{
public string Url { get; set; }
public DateTimeOffset ExpiresAt { get; set; }
public string ContentType { get; set; }
public string Filename { get; set; }
}
}
5 changes: 5 additions & 0 deletions Router/OrganizationRouter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,11 @@ public static string DeleteCertificate(string id)
return $"{RetrieveOrganization(id)}/certificate";
}

public static string ManifiestoDownloadUrl(string id)
{
return $"{RetrieveOrganization(id)}/manifiesto/download-url";
}

public static string GetTestApiKey(string id)
{
return $"{RetrieveOrganization(id)}/apikeys/test";
Expand Down
1 change: 1 addition & 0 deletions Wrappers/IOrganizationWrapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ public interface IOrganizationWrapper
Task<Organization> UploadLogoAsync(string id, Stream file, CancellationToken cancellationToken = default);
Task<Organization> UploadCertificateAsync(string id, Stream cerFile, Stream keyFile, string password, CancellationToken cancellationToken = default);
Task<Certificate> DeleteCertificateAsync(string id, CancellationToken cancellationToken = default);
Task<SignedDownloadUrl> DownloadManifiestoZipUrlAsync(string id, CancellationToken cancellationToken = default);
Task<Organization> UpdateLegalAsync(string id, Dictionary<string, object> data, CancellationToken cancellationToken = default);
Task<Organization> UpdateReceiptSettingsAsync(string id, Dictionary<string, object> data, CancellationToken cancellationToken = default);
Task<Organization> UpdateCustomizationAsync(string id, Dictionary<string, object> data, CancellationToken cancellationToken = default);
Expand Down
10 changes: 10 additions & 0 deletions Wrappers/OrganizationWrapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,16 @@ public async Task<Certificate> DeleteCertificateAsync(string id, CancellationTok
}
}

public async Task<SignedDownloadUrl> DownloadManifiestoZipUrlAsync(string id, CancellationToken cancellationToken = default)
{
using (var response = await client.GetAsync(Router.ManifiestoDownloadUrl(id), cancellationToken).ConfigureAwait(false))
{
await this.ThrowIfErrorAsync(response, cancellationToken).ConfigureAwait(false);
var resultString = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
return JsonConvert.DeserializeObject<SignedDownloadUrl>(resultString, this.jsonSettings);
}
}

public async Task<Organization> UpdateLegalAsync(string id, Dictionary<string, object> data, CancellationToken cancellationToken = default)
{
using (var content = new StringContent(JsonConvert.SerializeObject(data), Encoding.UTF8, "application/json"))
Expand Down
2 changes: 1 addition & 1 deletion facturapi-net.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
<Summary>SDK oficial de Facturapi para .NET para facturación electrónica en México (CFDI), envío de documentos, búsqueda y trazabilidad.</Summary>
<PackageTags>factura factura-electronica facturacion cfdi cfdi40 sat invoice invoicing facturapi mexico</PackageTags>
<Title>Facturapi</Title>
<Version>7.1.0</Version>
<Version>7.2.0</Version>
<PackageVersion>$(Version)</PackageVersion>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<PackageRequireLicenseAcceptance>false</PackageRequireLicenseAcceptance>
Expand Down
Loading