Site

Consumindo a API em C# / .NET v3

Um client HTTP como qualquer outro: app desktop, serviço Windows, mobile .NET MAUI, integração interna. A API não é exclusiva de launcher.

Na prática você tem dois padrões de Bearer:

  1. Token de login — usuário autentica em /api/login e recebe mcrm_…
  2. Token de serviço — você define $myToken no PHP e o client envia o mesmo valor; o servidor lê com request()->bearer_token()

Token de serviço

Útil para endpoints de status, sync ou jobs sem login de pessoa.

PHP (API)

$myToken = config('api.service_token');

public function status()
{
    $token = request()->bearer_token();

    if (!$token || !hash_equals((string) $myToken, (string) $token)) {
        return request()->json(['success' => false, 'error' => 'Unauthorized'], 401);
    }

    return request()->json(['success' => true, 'version' => '2.0.0']);
}

C# (client)

var myToken = "xxxxx-seu-segredo";

using var client = new HttpClient {BaseAddress = new Uri("https://seu-site.com/")};
client.DefaultRequestHeaders.Accept.Add(
    new MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Authorization =
    new AuthenticationHeaderValue("Bearer", myToken);

var res = await client.GetAsync("api/status");
var json = await res.Content.ReadAsStringAsync();
💡Mesma API de leitura
Não importa se o Bearer veio do /api/login ou do seu $myToken: no servidor você sempre usa request()->bearer_token() para extrair o valor limpo (sem o prefixo Bearer ).

Detalhes: Autenticação → Token de serviço.


Login de conta + Bearer (mcrm_…)

HttpClient

using System.Net.Http.Headers;
using System.Net.Http.Json;

public sealed class MucrmApiClient
{
    private readonly HttpClient _http;

    public MucrmApiClient(string baseUrl)
    {
        _http = new HttpClient {BaseAddress = new Uri(baseUrl.TrimEnd('/') + "/")};
        _http.DefaultRequestHeaders.Accept.Add(
            new MediaTypeWithQualityHeaderValue("application/json"));
    }

    public async Task<string> LoginAsync(string username, string password, CancellationToken ct = default)
    {
        var res = await _http.PostAsJsonAsync("api/login", new {username, password}, ct);
        var body = await res.Content.ReadFromJsonAsync<LoginResponse>(cancellationToken: ct)
                   ?? throw new InvalidOperationException("Resposta vazia");

        if (!res.IsSuccessStatusCode || !body.Success)
            throw new Exception(body.Error ?? $"HTTP {(int)res.StatusCode}");

        _http.DefaultRequestHeaders.Authorization =
            new AuthenticationHeaderValue("Bearer", body.Token);

        return body.Token;
    }

    public async Task<string> MeAsync(CancellationToken ct = default)
    {
        var res = await _http.PostAsync("api/me", content: null, ct);
        res.EnsureSuccessStatusCode();
        return await res.Content.ReadAsStringAsync(ct);
    }

    public async Task LogoutAsync(CancellationToken ct = default)
    {
        var res = await _http.PostAsync("api/logout", null, ct);
        res.EnsureSuccessStatusCode();
        _http.DefaultRequestHeaders.Authorization = null;
    }

    private sealed record LoginResponse(bool Success, string? Token, string? Error, int? Code);
}

Uso

var api = new MucrmApiClient("https://seu-site.com");
await api.LoginAsync(txtUser.Text, txtPass.Text);
var meJson = await api.MeAsync();
💡Secure storage
Não grave o Bearer em texto plano no disco. Prefira DPAPI / Credential Manager / memória do processo.

Tratando 422

if ((int)response.StatusCode == 422)
{
    var err = await response.Content.ReadFromJsonAsync<ValidationEnvelope>();
    // err.Errors["password"]
}

record ValidationEnvelope(string Message, Dictionary<string, string> Errors);

withoutCsrf

Clients HTTP (app, bot, SPA, desktop) não enviam CSRF de sessão. O grupo routes/api.php já usa 'withoutCsrf' => true. Veja Roteamento.

Próximo: Node.js · JavaScript.